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

    粘包分包问题

    # 如果使用异步方式 beginreceive() 如果开辟的数组足够大,是不会产生分包发送的问题,但是- - 足够大是多大….

    上一篇写了Socket通讯,这一篇整理一下粘包分包的问题, 主要思路是在字节数据前四个位置保存一个数据的长度后边保存数据,通过一个类进行存储传输过来的数据,再使用这个类进行解析.

    服务器

    namespace 服务器
    {
    //解析类
    class Message
        {
            private byte[] date = new byte[10240];
            public int startIndex = 0; //存储了多少字节的数据
    
            public byte[] Date
            {
                get { return date; }
            }
    
            public int ReMainSize//得到剩余date大小
            {
                get { return date.Length - startIndex; }
            }
    
            public void AddCount(int count) //添加数据
            {
                startIndex += count;
            }
    
            public void ReadMessage()
            {
    
                while (true)
                {
                    if (startIndex <= 4) //如果不大于4表示数据可能不完整.则不解析
                        return;
    
                    int count = BitConverter.ToInt32(date, 0); //将date中的前4个字节(当前数据完整的长度是多少)读取到
                    if ((startIndex - 4) >= count) //判断剩余的字节够不够,
                    {
    
                       // Console.WriteLine("count" + count);
                        string temp = Encoding.UTF8.GetString(date, 4, count); //如果够, 读取当前完整的记录
                        Console.WriteLine("startIndex" + startIndex);
                        Console.WriteLine("解析出来一条数据:" + temp);
                        Array.Copy(date, count + 4, date, 0, startIndex - count - 4);// 复制当前数组到自己(就是替换) 把date数据,从已经解析的位置开始,赋值到自己,赋值到自己的0开始到剩余的数据长度
                        startIndex -= (count + 4); //把startIndex的位置向前提,(减去刚刚解析的数据长度)
                    }
                    else
                    {
                        break;
                    }
    
                }
    
    
    
            }
    
        }
    
    
    
    
        class Program
        {
            static void Main(string[] args)
            {
                Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
                serverSocket.Bind(new IPEndPoint(IPAddress.Parse("10.6.0.38"), 88));
    
                serverSocket.Listen(19);
    
                serverSocket.BeginAccept(ClientAccept, serverSocket);//异步连接(回调函数,参数)
                Console.ReadLine();
    
            }
            //static byte[] buffer = new byte[1024];
            static Message msg = new Message();
            static void ClientAccept(IAsyncResult ar)
            {
    
    
                Socket serverSocket = ar.AsyncState as Socket;
    
                Socket clientSocket = serverSocket.EndAccept(ar);
    
                clientSocket.Send(Encoding.UTF8.GetBytes("hellooo"));
    
                clientSocket.BeginReceive(msg.Date, msg.startIndex, msg.ReMainSize, SocketFlags.None, ServerReceive, clientSocket);//(存储到的数据,从第几个位置开始存储,向里存的最大数量,标志,回调,参数)这里如果接收到的数据大于ReMainSize也不会超过这个ReMainSize,如果ReMainSize设置的太大, 大于接收到的数据,那么存储到msg.date中会报错
    
                serverSocket.BeginAccept(ClientAccept, serverSocket);//在这里继续进行异步连接,有点递归的意思
    
            }
    
            static void ServerReceive(IAsyncResult ar)
            {
                Socket clientSocket = null;
    
                try
                {
                    clientSocket = ar.AsyncState as Socket;
                    int len = clientSocket.EndReceive(ar);
    
                    if (len == 0)
                    {
                        clientSocket.Close();
                        return;
                    }
                    msg.AddCount(len);
    
                    msg.ReadMessage();//这里注意先手顺序, ↓这行代码一定要在之后
                    clientSocket.BeginReceive(msg.Date, msg.startIndex, msg.ReMainSize, SocketFlags.None, ServerReceive, clientSocket);//这里如果接收到的数据大于ReMainSize也不会超过这个ReMainSize,如果ReMainSize设置的太大, 大于接收到的数据,那么存储到msg.date中会报错
    
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    clientSocket.Close();
                }
    
    
                Console.ReadLine();
            }
        }
    }

    客户端

    namespace 客户端
    {
        class Program
        {
            static byte[] GetBytes(string date)
            {
                byte[] dateBytes = Encoding.UTF8.GetBytes(date);
                int len = dateBytes.Length;
                byte[] byteLengths = BitConverter.GetBytes(len);
                byte[] newBytes = byteLengths.Concat(dateBytes).ToArray();
                return newBytes;
            }
    
    
    
    
            static void Main(string[] args)
            {
    
                byte[] buffer = new byte[1024];
    
                Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
                clientSocket.Connect(new IPEndPoint(IPAddress.Parse("10.6.0.38"), 88));
    
                int len = clientSocket.Receive(buffer);
    
                Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, len));
    
                //while (true)
                //{
                //    string temp = Console.ReadLine();
    
                //    if (temp == "c")
                //    {
                //        clientSocket.Close();
                //        return;
                //    }
    
                //    byte[] tempByte = Encoding.UTF8.GetBytes(temp);
    
                //    clientSocket.Send(tempByte);
                //}
    
                for (int i = 0; i < 100; i++)
                {
                    clientSocket.Send(GetBytes(i.ToString()));
                }
    
                Console.ReadLine();
    
            }
        }
    }
    本博客所有内容均为原创,转载请注明出处.
  • 相关阅读:
    Linux系统中的load average
    通过数据库评估存储设备IO性能-Oracle11gIO校准功能介绍
    ORACLE查询字段中含有空格的数据
    JavaScript&Typescript中的时间
    LeetCode
    LeetCode
    面试问题及知识汇总
    Bootstrap布局容器与栅格系统
    JVM垃圾回收(GC)
    9. 专题
  • 原文地址:https://www.cnblogs.com/what-lee/p/8722937.html
Copyright © 2011-2022 走看看