Socket 循环接收消息 粘包 半包(C#)

Socket 循环接收消息 粘包 半包(C#)

猿掌柜
2021-03-17 / 2 评论 / 133 阅读 / 正在检测是否收录...

{mtitle}这两天在学习socket收发消息的问题,学到了新知识{/mtitle}

1、对于一次接收到大于接收缓存的消息,并且连续接收消息,两段消息可能同时被接受到一端缓存中,叫粘包;

2、收到的消息不足一个接收缓存,交半包;

 

程序的几个注意点:

1、必须要循环接收消息;

2、消息头必须要有长度标志字节(这里是用的前四个字节来保存实际消息体的长度);

3、除了接收缓存rev之外还需要一个cache缓存byte[] ,用来保存一条完整的消息;

4、cache缓存可能不足一个接收缓存,那后面不足的会有0 补充 ,半包;

5、cache缓存 可能刚好一个接收缓存,并且包含>= 1个完整消息(等于的时候无粘包,大于的时候有粘包);

6、cache缓存 大于一个接收缓存,这里需要循环接收(用长度标志字节来判断),直到接收到 >= 一个完整消息,还是5、的情况;

7、接受完一个完整消息后,需要清空缓存,或者将有粘包的字节重新拷贝到cache缓存;

Socket soc = obj as Socket;
int recvlen = 0;
byte[] cacheBuf = null;
byte[] recvBuf = new byte[100];
if (soc != null)
{
    while ((recvlen = soc.Receive(recvBuf)) > 0)
    {
        if (cacheBuf == null)
        {
            cacheBuf = new byte[recvlen];
            Array.Copy(recvBuf, cacheBuf, recvlen);
        }
        else
        {
            byte[] t = new byte[cacheBuf.Length + recvlen];
            Array.Copy(cacheBuf, t, cacheBuf.Length);
            Array.Copy(recvBuf, 0, t, cacheBuf.Length, recvlen);
            cacheBuf = t;
        }
        if (cacheBuf.Length <= 4)
            continue;
        int msgl = BitConverter.ToInt32(cacheBuf, 0);
        while (cacheBuf!=null && msgl + 4 <= cacheBuf.Length)
        {
            byte[] msgbyte = new byte[msgl];
            Array.Copy(cacheBuf, 4, msgbyte, 0, msgl);
            test(msgbyte,soc);//拿到完整消息,具体消息操作
            if (msgl + 4 == cacheBuf.Length)
            {
                cacheBuf = null;
            }
            else
            {
                byte[] tmpByte = new byte[cacheBuf.Length - msgl - 4];
                Array.Copy(cacheBuf, msgl + 4, tmpByte, 0, cacheBuf.Length - msgl - 4);
                cacheBuf = tmpByte;
            }
        }
    }
}
4

评论 (2)

取消
  1. 头像
    lnote
    MacOS · QQ Browser

    文章很有不错

    回复
  2. 头像
    游客
    Windows 10 · QQ Browser

    学习了表情

    回复