tcp组包1——为啥要组包

本文主要介绍下,如果不进行组包的时候,会出现什么情况:
下面是服务端,一次性发送1000条数据:

public void AddProtocolMessage()
        {
    
    
            Google.Protobuf.Examples.Person.Person person = new Google.Protobuf.Examples.Person.Person();
            person.Id = 1;
            person.Name = "xiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming" +
                "xiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好a" +
                "xiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好a" +
                "xiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好a" +
                "xiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好a" +
                "xiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好a" +
                "xiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好a" +
                "xiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好a" +
                "xiaoming你好axiaoming你好axiaoming你好axiaoming你好axxiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好a" +
                "xiaoming你好axiaoming你好axiaoming你好axiaoming你好a你好aiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好a" +
                "xiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好axiaoming你好a你好a";
            person.Email = "[email protected]";

            Google.Protobuf.Examples.Person.Person.Types.PhoneNumber phoneNumber = new Google.Protobuf.Examples.Person.Person.Types.PhoneNumber();
            phoneNumber.Number = "123456";
            phoneNumber.Type = Google.Protobuf.Examples.Person.Person.Types.PhoneType.Mobile;
            person.Phones.Add(phoneNumber);

            MemoryStream ms = new MemoryStream();
            Google.Protobuf.CodedOutputStream codedOutput = new Google.Protobuf.CodedOutputStream(ms);
            person.WriteTo(codedOutput);
            codedOutput.Flush();
            byte[] buffer = ms.GetBuffer();
            long len = ms.Length;
            Message message = new Message();
            message.m_data = buffer;
            for (int i = 0; i < 1000; ++i)
            {
    
    
                m_sendMessages.Enqueue(message);
            }
        }

客户端在接收的地方:

        static int count = 0;
        static int totalSize = 0;
        private void OnReceiveCallback(IAsyncResult ar)
        {
    
    
            Socket sock = (Socket)ar.AsyncState;
            int len = sock.EndReceive(ar);
            totalSize += len;
            Console.WriteLine("receive=" + count++ + "  len=" + len + "  totalSize=" + totalSize);
            //m_receiveStream.Write(m_receiveBuffer, 0, len);
            //m_receiveStream.Seek(0, SeekOrigin.Begin);
            //Google.Protobuf.Examples.Person.Person person = Google.Protobuf.Examples.Person.Person.Parser.ParseFrom(m_receiveStream);
            m_clientSocket.BeginReceive(m_receiveBuffer, 0, m_receiveBuffer.Length, SocketFlags.None, OnReceiveCallback, m_clientSocket);
        }

这里的m_receiveBuffer我们开的是128
在这里插入图片描述
服务器总共发送了1000次,而客户端接收了13204次,最后一次接收的大小是16字节。总量是不变的。1690000字节。

而我们的协议呢?是1690个字节,所以在接收的地方,要将多次接收到的数据组装成一个有效的数据包才行。

那我们想,如果是不是buffer开的大一点,就好了,于是我们开成4096个字节大小。
在这里插入图片描述

服务端发送了1000次,但是客户端本次接收了964次,咦?
接收的次数小于了发送的次数,那说明,比如有一次接收的字节数大于发送的字节数1690个字节。
在这里插入图片描述
果然,红色框内接收的字节数大于发送的1690个字节。

所以这就说明了,buffer开的大和开的小,都不能准确的定义,一次接收的数据就是一个完整的包,有可能是大于一个包,也可能是小于一个包。
故,必须标记一个包的大小,然后根据包的大小去组装成一个有效包。

おすすめ

転載: blog.csdn.net/wodownload2/article/details/121334265