TCP粘包和拆包

Posted by JimWang on 2021-02-10

TCP粘包和拆包

什么是粘包和拆包

为了提高带宽利用率,tcp协议会使用Nagle算法,将多个数据包打包成一个tcp报文发送出去,这就是所谓的粘包。

而如果通讯的一端发送的数据包超过一次tcp报文所能传输的最大值MTU时,就会将一个数据包拆成多个最大tcp长度的tcp报文分开传输,这就叫做拆包。

MTU:

泛指通讯协议中的最大传输单元。一般用来说明TCP/IP四层协议中数据链路层的最大传输单元,不同类型的网络MTU也会不同,我们普遍使用的以太网的MTU是1500,即最大只能传输1500字节的数据帧。可以通过ifconfig命令查看电脑各个网卡的MTU。

MSS:

指TCP建立连接后双方约定的可传输的最大TCP报文长度,是TCP用来限制应用层可发送的最大字节数。如果底层的MTU是1500byte,则 MSS = 1500- 20(IP Header) -20 (TCP Header) = 1460 byte。

拆包的两种方式

基于长度实现的两种方式

  • 使用固定长度,所有的应用层消息都是用统一的大小
  • 使用不固定的长度,但是需要在应用层协议的头部中增加表示负载长度的字段。

基于特定规则的方式

  • 例如使用TCP发送JSON数据,接收方可以根据接收到的数据是否能够被解析成合法的JSON判断消息是否终结。

出现粘包的原因

当发送方连续的向客户端发送n条数据(循环发送),按照我们预想的,server端应该受到n条数据。然而server却收到了小于n条数据,而且每条数据的长短不一,有很多不是同一次发送的数据包却粘连到了一起,这就是粘包现象。

粘包可能发生在发送端也可能发生在接收端:

  • 由Nagle算法造成的发送端粘包:Nagle算法是一种改善网络传输效率的算法。简单的来说就是当我们提交一段数据给TCP发送的时候,TCP并不会立即的发送这段数据,而是等一小段时间看看在等待的时间内是否还有其他的数据要发送,若有则一次性把两段数据发送出去。
  • 接收端接收不及时造成的粘包:接收端TCP会把收到的数据写入一个缓冲区,然后通知应用层取数据。当应用层由于某些原因不能及时的把数据取走,就会造成TCP缓冲区堆积,存放了几段数据包,造成粘包现象。

解决粘包

出现粘包的关键在于接收方不能够确定将要接收的数据包的大小,因此我们需要手动对数据进行封包和拆包操作。

封包封包就是给一段数据加上包头,这样一来数据包就分为包头和包体两个部分内容了(过滤非法包时封包还会加入包尾)。包头部分的长度是固定的,并且它存储了包体的长度。

**拆包:**根据包头的长度固定以及包头中所包含的包体的长度就能够正确的实现拆分出一个完整的数据包。

UDP有粘包现象吗

UDP没有粘包现象,由于UDP发送数据的时候,没有经过Nagle算法优化,不会将多个小包合并到一次发送。另外,在UDP协议的接收端,采用的是链式结构来记录每一个到达的UDP包,这样接收端一次recv只会从socket缓冲区读取一个数据包。也就是说,发送端send了几次,接收端必须recv几次(无论recv时指定了多大的缓冲区)