粘包和分包

本文介绍了TCP粘包现象,即发送方若干包数据到接收方时粘成一包,原因可能是发送方TCP协议优化或接收方用户进程不及时接收数据。还提到分包处理,以及解决粘包问题的思路,如在数据包固定位置封装长度信息,同时对数据长度做校验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

01:指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。分包是指在出现粘包的时候我们的接收方要进行分包处理。
粘包问题显示

 for (int i = 0; i < 200; i++)
            {
                byte[] data = System.Text.Encoding.UTF8.GetBytes(i.ToString());
                //异步发送消息
                clientSocket.BeginSend(data, 0, data.Length,SocketFlags.None,null,null);       

在这里插入图片描述
02:解决思路
在数据包中的固定位置封装数据包的长度信息(或可计算数据包总长度的信息),服务器接收到数据后,先是解析包长度,然后根据包长度截取数据包(此种方式常出现于自定义协议中),但是有个小问题就是如果客户端第一个数据包数据长度封装的有错误,那么很可能就会导致后面接收到的所有数据包都解析出错(由于TCP建立连接后流式传输机制),只有客户端关闭连接后重新打开才可以消除此问题,我在处理这个问题的时候对数据长度做了校验,会适时的对接收到的有问题的包进行人为的丢弃处理(客户端有自动重发机制,故而在应用层不会导致数据的不完整性)
在这里插入图片描述
在这里插入图片描述
03:字符串和值类型转换成字节数据
在这里插入图片描述
04:

//以字节数组的形式返回指定的 32 位有符号整数值
 int a = 1000000;
  byte[] data=BitConverter.GetBytes(a);
foreach (var item in data)
 {
   Console.WriteLine(item);
 }

//返回由字节数组中指定位置的四个字节转换来的 32 位有符号整数。
 byte[] data1=new byte[4]{1,1,0,0};
  int count=BitConverter.ToInt32(data1,0);
 Console.WriteLine(count);

在这里插入图片描述

05:在客户端发送数据的时候加上数据长度

 b6 = b4.Concat(b5).ToArray();//合并两个数组总结 这种linq方法适用于所有数组
 

    public static class Message
    {
        //包装消息
        public static Byte[] GetBytes(string str)
        {
            byte[] data1=System.Text.Encoding.UTF8.GetBytes(str);
            int length = data1.Length; //数据的长度
            byte[] data2 = BitConverter.GetBytes(length); //长度转换为四个字节的数组
            return data2.Concat(data1).ToArray();
        }
    }

06:解析客户端发送过来的数据

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SocketServer
{
    /// <summary>
    /// 处理接收过来的数据
    /// </summary>
    class Message
    {
        private byte[] data = new byte[1024];
        private int startIndex = 0;//我们存取了多少个字节的数据在数组里面

        public byte[] Data
        {
            get { return data; }
        }
        public int StartIndex
        {
            get { return startIndex; }
        }

        //更新获取的数据长度
        public void AddCount(int count)
        {
            startIndex += count;
        }
        public int RemainSize //剩余空间
        {
            get { return data.Length - startIndex; }
        }

        /// <summary>
        /// 解析数据或者叫做读取数据
        /// </summary>
        public void ReadMessage()
        {
            while (true)
            {
                if (startIndex <= 4)
                {
                    return;
                }
                // 读取前四个字节的数据(数组前四个字节保存的是传过来消息的元素个数)
                int length = BitConverter.ToInt32(data, 0);//数据的长度
                if ((startIndex - 4) >= length) //数据读取完整
                {
                    string message = System.Text.Encoding.UTF8.GetString(data, 4, length);
                    Console.WriteLine("收到了客户端的消息:"+message);
                    //归零
                   Array.Copy(data,length+4,data,0,startIndex-4-length);
                   startIndex -= (4 + length);
                }
                else
                {
                    break;
                }
            }
            
        }
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在网络通信中,由于数据传输的特性,会出现分包的问题。 (Packet Sticking)是指发送方发送的数据被接收方连续接收到,多个数据被黏在一起,导致接收方无法正确解析数据。这可能是因为发送方发送的数据没有明确的边界,接收方无法确定每个数据的开始结束位置。 分包(Packet Splitting)是指发送方发送的数据被接收方拆分成多个数据接收。这可能是因为发送方发送的数据过大,导致网络传输过程中被拆分成多个小进行传输。 出现分包问题的原因主要有以下几点: 1. 发送方连续发送多个数据时,底层传输协议可能会将多个数据合并成一个大的数据块进行传输,导致接收方接收到的数据不完整。 2. 发送方发送的数据大小超过了接收方的缓冲区大小,导致数据被拆分成多个小进行传输。 3. 网络传输中存在延迟或拥塞,导致数据到达顺序发生变化。 为了解决分包问题,可以采用以下几种方法: 1. 使用固定长度的数据:在每个数据的前面添加固定长度的头部信息,指示该数据的长度,接收方根据头部信息来切分数据。 2. 使用特殊字符作为分隔符:在数据之间添加特殊字符作为分隔符,接收方根据分隔符来切分数据。 3. 使用长度字段:在数据的头部添加一个表示数据长度的字段,接收方根据长度字段来切分数据。 4. 使用消息边界:在传输协议中定义消息边界,保证每个数据都是一个完整的消息。 具体选择哪种方法取决于你的应用需求实际情况。在实际开发中,可以根据协议规范或业界常用的做法来处理分包问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值