zoukankan      html  css  js  c++  java
  • Socket解决粘包问题2

    在AsynServer中对接收函数增加接收判断,如果收到客户端发送的请求信息,则发送10个测试包给发送端,否则继续接收,修改后的接收代码如下:

            private void AsynReceive()
            {
                byte[] data = new byte[1024];//接收缓存
                string receiveStr;
                string[] sendArr = PackageBuilder.BuildPackage(10);//生成发送数组,10个包
                socket.BeginReceive(data, 0, data.Length, SocketFlags.None, asyncResult => {
                    int length = socket.EndReceive(asyncResult);
                
                    receiveStr = Encoding.ASCII.GetString(data, 0, length);//获取缓存中的信息
                                                                           //    Console.WriteLine(receiveStr);
    
                    if (receiveStr == "1")      //标志字符'1',如果收到1,则发送测试包给客户端,如果不是1,继续接受
                    {
                        for (int i = 0; i < 10; i++)
                        {
                            Console.WriteLine("第{0}次发送:",i);
                            AsynSend(sendArr[i]);
                       //     Thread.Sleep(200);
                        }
    
                    }
                    else
                        AsynReceive();
                }, null);
    
    
            }
    View Cosde

    其中if (receiveStr == "1")是接收判断,如果收到客户端发来的1,则发送测试包给客户端,如果不是1,继续接收。因为是异步发送,所以Console.WriteLine("第{0}次发送:",i);显示可能和发送数据不同步,但肯定是发送了10次。

    测试一下,发送10次,接收端收到结果如下:

    发了10次,而只收了8次,从上图中我们可以发现第6次和第7次发生了粘包,两个包被当作1个包接收了,如果你编写解包程序时不考虑粘包,那么解包循环在第7次解包时会抛异常。当然一种快捷的避免粘包方式是在发送函数的 AsynSend(sendArr[i]);下面加上Thread.Sleep(200);减少发送频率,但这不是长久之计,接下来我们进入客户端来处理粘包问题。

    客户端主要是修改了SyncReceive方法,使用StringBuilder来做接收,因为StringBuilder较于string而言,增加字符串,删除字符串的效率比较高,代码如下:

     string[] receiveArr = new string[10];//用于存储接收到的数据
            int arri=0;//数组位序
            public virtual void SyncReceive()
            {
                //StringBuilder sb = new StringBuilder(1024*1024);
                StringBuilder receiveSb = new StringBuilder();      //接收字符串buffer
                string receiveStr;            //解包过程中用于 中间处理  
                int index;       //位序,用于解包
                int dataLength; //存储接收包中的数据长度
                int i = 0;
                Thread th = new Thread(() =>
                {
                    while (receiveFlag)
                    {
                        byte[] buffer = new byte[1024];
                        int r = socket.Receive(buffer);
                        string str = Encoding.ASCII.GetString(buffer, 0, r);    //只是用来显示
                        Console.WriteLine("第{0}次收到数据:{1}",i++,str);
                        Console.WriteLine();
    
                        receiveSb.Append(str);              //存储接收字符串,可能存多个包
                        receiveStr = receiveSb.ToString();
                        index = receiveStr.IndexOf("data:");//可能有多个"data"
    
                        while (index > 1)
                        {
                            dataLength = int.Parse(receiveStr.Substring(index - 2, 2));//数据长度规定为2个字节
                            receiveArr[arri] = receiveStr.Substring(index, dataLength);//保存数据到数组中
                            Console.WriteLine("保存的数据数组[{0}]:{1}",arri,receiveArr[arri++]);
                            receiveSb.Remove(0, 10 + dataLength);//包头+数据长度字节共10个字节"HEAD|H1|38",后面是数据"data:xxxxxxxxxxxxxxxxxxxx"
                            receiveStr = receiveSb.ToString();
                            index = receiveStr.IndexOf("data:");//寻找下一个"data",如果没有跳出循环
                        }
                      
                      
                            //sb.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, r));
                        }
                });
                th.Start();
               
            }
    View Code

    方法上面加了两个全局变量,receiveArr是一个数组,用于保存接收到的实时数据,这些数据可以用于前台展示,也可以直接保存到数据库;arri是数组位序,运行结果如下:

    如图所示,客户端接收了7次数据,第一次有4个包粘在了一起,但我们通过合适的解包,依然将10次数据分开保存在字符串数组中。

    客户端要先发送"1"标志给客户端才能执行上面的程序,     SynSend("1");

    程序的源码下载地址:

    链接:http://pan.baidu.com/s/1nvfa8lF 密码:zjoa

    粘包的处理是比较简单的,更麻烦的是分包,虽然不常见,但也要考虑,后面考虑做一下分包的处理,程序写的比较毛糙,如有不足之处希望大家指出。

  • 相关阅读:
    移动Web应用开发入门指南——视觉篇
    Dapper的完整扩展(转)
    Dapper.net 在Parameterized时对于String的扩展(转)
    Entity Framework 5.0
    用事实说话,成熟的ORM性能不是瓶颈,灵活性不是问题:EF5.0、PDF.NET5.0、Dapper原理分析与测试手记(转)
    雅虎团队:网站性能优化的35条黄金守则(转)
    在window server 2008 64位系统上 发布网站的过程中遇到的问题(转)
    sqlserver能否调用webservice发送短信呢?
    数据库优化方案(转)
    SQL点滴之编辑数据(转)
  • 原文地址:https://www.cnblogs.com/gongheng/p/5699092.html
Copyright © 2011-2022 走看看