一、粘包/半包介绍
1:粘包
粘包(Packet Concatenation)通常发生在基于流式传输协议(如 TCP)的通信中,因为 TCP 是面向流的传输协议,它不保证数据包的边界,而是将数据视为连续的字节流,它表示客户端发送多条消息,服务端只收到了一条消息
2:半包
半包(Half Packet)与粘包问题相反。在半包问题中,接收端接收到的数据包不完整,即接收到的数据包只是完整数据包的一部分,无法完整地解析和处理。
3:原因
①网络延迟/阻塞
②发送方连续发送数据
③接收端缓冲区大小限制
④数据包丢失
二、粘包/半包解决方案
1:长度信息法
在每个数据包前面加上长度信息,每次接收数据后,先读取长度,如果缓冲区数据长度大于要取的字节数,则取出相应字节,否则等待下一次接收,举个例子
①客户端第一次发送包含长度信息的内容
②客户端第二次发送包含长度信息的内容
③服务端第一次接收到了4个字节,存入缓冲区,但是这时候并不处理,因为收到了10,所以要等到11个字节完整再处理
④服务端等到客户端发送剩下的7个字节,但是第二次接收到了9个字节,服务端把之前的6个字节再读取,然后拼接,把10helloworld进行处理,读取到标志长度4,等待下次处理
⑤服务端最后一次收到ove,就把之前的l一起拼接,返回完整的4love
*一般的游戏是16位的整型数来存放长度信息
2:固定长度法
每次都发送相同长度的数据,一次不足的数据用.来补充,.位补充字符,没有实际意义
如果接收到的字符数大于10,就只提取前10个字符
3:结束符号法
规定一个结束符号作为消息的分隔符,比如Hello$World就是两条信息
三、代码示例
1:发送数据
byte[] bodyBytes = System.Text.Encoding.Default.GetBytes(SendStr);
Int16 len = (Int16)bodyBytes.Length;
//把长度转化为Int16
byte[] lenBytes = BitConverter.GetBytes(len);
//此时SendBytes包含长度字符串和内容字符串
byte[] sendBytes = lenBytes.Concat(bodyBytes).ToArray();
2:接收数据
定义一个接收缓冲区和接收缓冲区长度。缓冲区会保存尚未处理的数据
//接收缓冲区
byte[] readBuff = new byte[1024];
//接收缓冲区长度
int buffCount = 0;
之前的BeginReceive函数原型如下:
public IAsyncResult BeginReceive ( byte[