TCPIP / 粘包和拆包的定义以及解决办法

一、粘包

1、定义

指发送方发送的若干数据包在接收方接收时粘成一团,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

2、产生的原因

(1)发送方的原因

TCP默认使用 Nagle 算法,而 Nagle 算法主要做如下两件事情:

  • 只有上一个分组得到确认,才发送下一个分组。
  • 收集多个小分组,在一个确认到来时一起发送。

Nagle 算法造成了发送方可能存在粘包现象。

(2)接收端的原因

接收端接收到分组时,应用层并不会立即处理,接收端将接收到的分组放到接收缓存中,然后应用程序主动从接收缓存中读取分组,当接收端接收分组的速度大于应用程序读取分组的速度时,多个包就会被存至缓存。应用程序读取时,就会读到多个首尾相连在一起的包。

3、什么时候需要处理 TCP 粘包问题。

  • 如果发送方的多个分组本来就是同一个数据的不同部分,比如一个很大的文件分成多个分组发送,这时不需要处理TCP粘包问题。
  • 如果多个分组毫不相干,甚至是并联关系,则一定要处理TCP粘包问题。

二、拆包

1、定义

发送方将一个数据包拆分成了多个数据包进行传送。

2、产生的原因

  • 要发送的数据大于 TCP 剩余缓冲区的大小。
  • 要发送的数据大于 MSS 最大报文长度。

三、如何处理TCP粘包和TCP拆包问题

无论是TCP拆包还是TCP粘包本质问题都在于无法区分包的界限,可以采用以下三种方式来区分包的界限

  1. 消息数据固定长度,但是浪费存储和网络资源。
  2. 使用分割符来区分包的界限。
  3. 数据包的头部中增加数据包长度字段。

四、代码示栗

#pragma pack(1)

struct XMNPkgHeader
{
    // 报文的总长度(包头 + 包体)。
    unsigned short pkglen;

    // 消息类型的代码,用于区别不同的命令(消息)。
    unsigned short msgcode;

    // CRC32 校验,用于防止接收到的数据和 client 发送的数据不符的问题。
    int crc32;
};

#pragma pack()

之所以使用 pack(1) ,目的是让包头大小更紧凑,节约流量。 由于包头的大小(headerlen)是固定的,通过 pkglen 就可以知道包体的大小(bodylen = pkglen - headerlen)。

在已知包头和包体的长度的情况下,接受数据包的时候,首先可以接收 headerlen 大小的数据,如果接收的数据不够,则下次接收包头剩余的数据,直至包头数据接收完毕。

包头数据接收完毕之后,再接收 bodylen 大小的数据,如果接收的数据不足,则接收剩下的包体的数据,直至包体的数据接收完毕。

五、总结

TCP 之所以存在拆包和粘包问题,本质就是 TCP 是面向字节流的,而 UDP 是面向报文的!

六、源码链接

https://github.com/xuchanglong/XMoon

 

(SAW:Game Over!)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值