解决C#-Unity的同步TCP通信时的分包黏包问题

前文        

        今天学习了唐老师课程中关于分包黏包问题的解决方案,个人感觉不是很好理解,自己尝试实现并验证了可行性,本着分享的目的在这里介绍一下。

        首先叠个甲,个人水平有限,且目前刚接触网络编程相关,这里只是给出我当下想出的一个实现思路,如果发现了问题或者优化方案欢迎评论ovo

什么是分包,黏包?

        是在网络通信中由于各种因素(网络环境、API规则等)造成的消息与消息之间出现的两种状态。

        分包:一个消息分成多个消息发送。

        黏包:多个消息合并成一个消息发送。

如何解决分包黏包?

        前置信息:对于一个消息msg,为了区分它属于哪个自定义类,我们在其前面加上一个int标识(4位byte),也就是人为给每个自定义类规定一个id,消息的格式为:消息体的id+消息的内容(消息体)。

        利用这个思路,我们可以在此基础上加上一个消息体的长度len,同样为int类型(4位byte),每次解析消息时通过解出来的id和len确定消息体的类型和长度,从而避免分包黏包造成的无法解析出正确的msg的情况,消息的格式为:消息体的id+消息体的长度len+消息的内容(消息体)

实现思路

        这里只给出核心代码及思路,也就是如何对收到的消息的处理因为我懒

代码实现

    private byte[] cache = new byte[1024 * 1024];
    private int begin = 0, end = 0;
    private int id = -1, len = -1;
    private void HandleReceiveMsg(byte[] bytes, int receiveNum)
    {
        //将byte放入cache
        bytes.CopyTo(cache, end);
        end += receiveNum;

        //不断解析直到无法操作,保证离开时cache都是无法直接处理的状态
        while (true)
        {
            //得到id,len
            if (id == -1 && len == -1 && end - begin < 8) return;
            if (id == -1 && len == -1)
            {
                id = BitConverter.ToInt32(cache, begin);
                begin += 4;
                len = BitConverter.ToInt32(cache, begin);
                begin += 4;
            }
            
            //判断能否处理
            //  否,直接退出
            if (end - begin < len) return;
            //  能,解析出一条数据(处理完记得将id,len归为-1)
            BaseMsg msg = null;
            switch (id)
            {
                case 1001:
                    PlayerMsg playerMsg = new PlayerMsg();
                    playerMsg.Reading(cache, begin);
                    msg = playerMsg;
                    break;
                default:
                    break;
            }
            if(msg!=null)
                receiveQueue.Enqueue(msg);
            begin += len;
            id = -1;
            len = -1;
            
            //解析完一次后,将处理完的内容从缓存中弹出
            Array.Copy(cache,begin,cache,0,end-begin);
            end -= begin;
            begin = 0;
        }
    }

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值