Socket Tcp接收粘包处理

什么是粘包?

比如:通过Socket发2条不一样长度的数据,"abc"和"defg"。因为Socket的数据不是你请求发就立即发送的,有时候为了减少网络交互次数,会把几小的个数据凑一凑一起发送。

如果前面的被凑到一起发送了"abcdefg",就出现了粘包。

 

如何解决粘包问题?

发送数据的时候,在数据里带上这个数据的长度信息,这样就算多个数据被凑在一起发送,我们也能根据每个数据的长度信息来把他们区分出来。

上面的数据就变成:3abc,4defg;其中:3表示3个字节,utf-8字符串abc占3个字节;4表示4个字节。

 

代码 

private const int Packet_Head_Len = 4; //包头4字节, 一个int

private void RecvLoop(Socket socket)
{
    byte[] buff = new byte[8 * 1024]; //假设单个数据包不会超过这个大小
int notReadLen = 0; while (true) { try { int buffRemainLen = buff.Length - notReadLen; if (buffRemainLen <= 0) //数据包超过buff的大小了 break; int recvLen = socket.Receive(buff, notReadLen, buffRemainLen, 0, out var errCode); if (0 == recvLen) //服务端把该连接Shutdown或Close了 break; notReadLen += recvLen; int readedLen = 0; while (IsPacketReady(buff, readedLen, notReadLen, out var bodyLen)) { var str = Encoding.UTF8.GetString(buff, readedLen + Packet_Head_Len, bodyLen); //todo: 数据包处理 notReadLen -= Packet_Head_Len; //包头 notReadLen -= bodyLen; //下一个包的数据 readedLen += SocketHelper.Packet_Head_Len; readedLen += bodyLen; } if (notReadLen > 0) //如果有下一个包的数据, 移到buff开头 Buffer.BlockCopy(buff, readedLen, buff, 0, notReadLen); } catch (Exception ex) { //todo: 打印错误信息 } } } //检查数据是否都已经接收到了 public static bool IsPacketReady(byte[] buff, int readedLen, int notReadLen, out int bodyLen) { bodyLen = 0; if (notReadLen < Packet_Head_Len) return false; bodyLen = BitConverter.ToInt32(buff, readedLen); if (notReadLen < Packet_Head_Len + bodyLen) return false; return true; }

 

posted @ 2024-01-21 14:09  yanghui01  阅读(24)  评论(0编辑  收藏  举报