CSharp中Socket网络编程(三)自定义通信传输协议 您所在的位置:网站首页 网络协议类型和代码 CSharp中Socket网络编程(三)自定义通信传输协议

CSharp中Socket网络编程(三)自定义通信传输协议

2023-07-29 16:43| 来源: 网络整理| 查看: 265

第一部分:整个通信过程梳理;文末附全套代码; 第二部分:重要bug完善; 本篇为第三部分:消息类型编码:自定义通信协议。 第四部分:全套代码 通信协议这事:

我们希望在通信中除了传输信息以外,还可以发送图片,还可以实现窗口震动。此时涉及发送数据的类型问题。对于接收方来说,并不知道发送方发送出来的格式,因此如果按照原来解码为字符串类型则不再适用。这事需要双方事先约定好。

发送以0开头的字节数组代表字符串类型,发送以1开头的字节数组代表文件,发送以2开头的字节数组代表震动。

0:发送消息:

我们原来的代码如此。点击按钮,直接将对话框中的文本转为字节流发送。

private void btnSend_Click(object sender, EventArgs e) { string str = txtMsg.Text; byte[] buffer = Encoding.UTF8.GetBytes(str); dicSocket[cboUsers.SelectedItem.ToString()].Send(buffer); }

 当前需要在字节之前加上一位0,表示为传输的为字符串。

数组的长度一旦声明就不可改变了。

为此需要声明一个新数组,将协议类型头数据写入,然后再接上原来的数组。实现字节编码。然后解码的时候,先解析字节数组中的协议类型头数据。

解决方案一:新数组的长度为buffer.Length+1。然后NewBuffer[0]=0。将剩余的buffer值循环,赋值给newBuffer。

解决方案二:数组的长度不可改变,但是泛型集合的长度可以改变。并且可以将数组添加到集合中。并且可以将集合转化为数组。

采用第二种方案最简单。

private void btnSend_Click(object sender, EventArgs e) { string str = txtMsg.Text; byte[] buffer = Encoding.UTF8.GetBytes(str); List list = new List(); list.Add(0); list.AddRange(buffer); // 将泛型集合转化为数组。 byte[] NewBuffer = list.ToArray(); //buffer = list.ToArray(); // 因为类型长度不同,无法赋值。所以新建。 // dicSocket[cboUsers.SelectedItem.ToString()].Send(buffer); dicSocket[cboUsers.SelectedItem.ToString()].Send(NewBuffer); }

 那么相应的接受端也要先解析第一个字节数组情况。注意一点:在转码时,转码长度为r-1。 

void Receive() { try { while (true) { byte[] buffer = new byte[1024 * 1024 * 10]; int r = socketSend.Receive(buffer); if (r == 0) { break; } if (buffer[0]==0) { string str = Encoding.UTF8.GetString(buffer, 1, r-1); ShowMsg(socketSend.RemoteEndPoint.ToString() + ":" + str); } else if (buffer[0]==1) { // 见下面文件传输 } else if (buffer[0]==2) { // 见下面抖动 } } } catch { } } 1:发送文件

首先通过【选择文件】按钮将文件选中,然后显示在文本框中,然后点击【发送文件】按钮将文件发出。接受端(客户端)解析字节头,识别1后,打开对话框,选择保存文件路径。并保存文件。

设置按钮显示文件目录,选中文件并显示:

private void btnSelect_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.InitialDirectory = @"C:\Users\futurecloud\Desktop"; ofd.Title="请选择你要传输的文件"; ofd.Filter = "所有文件|*.*"; ofd.ShowDialog(); //this.txtPath.Text = ofd.SafeFileName; txtPath.Text = ofd.FileName; }

为了发送文件,首先创建一个文件流来读取文件。然后将字节流数组前加上标识符号1,发送给客户端。此操作在【发送文件】中完成。

private void btnSendFile_Click(object sender, EventArgs e) { string path = txtPath.Text; using (FileStream fsRead=new FileStream(path, FileMode.Open, FileAccess.Read)) { byte[] buffer = new byte[1024 * 1024 * 10]; int r = fsRead.Read(buffer, 0, buffer.Length); List list = new List(); list.Add(1); list.AddRange(buffer); byte[] newBuffer = list.ToArray(); // send有很多重载:有限制大小的。 dicSocket[cboUsers.SelectedItem.ToString()].Send(newBuffer, 0, r+1, SocketFlags.None); } }

服务器端完成发送,客户端需要将解码,并打开一个保存文件对话框。

// 接续上面Recive()中的代码。 else if (buffer[0]==1) { SaveFileDialog sfd = new SaveFileDialog(); sfd.InitialDirectory = @"C:\Users\futurecloud\Desktop"; sfd.Title = "请选择你要保存的文件路径:"; sfd.Filter = "所有文件|*.*"; sfd.ShowDialog(this); // 不加这个this这个框不弹出来。 // 写入文件: string path = sfd.FileName; using (FileStream fsWrite = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write)) { fsWrite.Write(buffer,1,r-1); } //ShowMsg("写入文件成功。"); MessageBox.Show("文件写入成功"); }

至此文件发送功能完成:后续可以进一步完善的方案:在1后面继续添加一位:如果是10则为图片,如果是11则是txt,如果是12则是word。等等。依次类推。 

2:震动

点击震动,只需要传输一个2过去就够了。

private void btnZD_Click(object sender, EventArgs e) { byte[] buffer = new byte[1]; buffer[0] = 2; dicSocket[cboUsers.SelectedItem.ToString()].Send(buffer); }

如何实现震动效果,说白了,就是在一定时间内,让窗体震动,或者,指定窗体震动次数。

/// /// 实现震动效果 /// void ZD() { for (int i = 0; i < 500; i++) { //this.Location = new Point(200, 200); //this.Location = new Point(210, 210); this.Location = new Point(this.Location.X, this.Location.Y); this.Location = new Point(this.Location.X+10, this.Location.Y+10); this.Location = new Point(this.Location.X-10, this.Location.Y-10); } } else if (buffer[0]==2) { ZD(); }

如果有其他设置,一样可以修改字节数组来改变。

我有一个想法:(可能TCP用不到)

我们在传输的时候有丢包的担心,所以

我们给我们要发送的报文编号,如果接收方接收到的报文编号不连续,则要求重新发送某个缺失报文。

场景:每次数据更新的时候发送更新的点位数据。

[编号0]+更新数据

[编号1]+更新数据

......

[编号n]+更新数据

接收方:在接收到某个报文[n]后,先查看编号列表,如果编号[n-1]已经在了,则直接解析,如果[n-1]不存在,则要求重新发送编号[n-1]的报文,同时查看[n-2]是否存在。。以此类推。

类推几个看需求。有时候类推一个,有时候全部类推。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有