摘要:TCP层在网络传输过程可能会把几个小的协议包合并成一个大的包来发送(粘包),也可能把一个完整的协议包分拆成几个小的包分开发送(拆包)。
粘包/拆包的概念
我们知道TCP是一种面向流的运输层协议,通过TCP传输数据就像流水那样,没有界限。但是我们的业务数据是有界限的,一般我们会订好协议,我们可以把提供完整协议的一串数据流叫一个协议包。由于TCP不了解上层的协议包概念,TCP层在网络传输过程可能会把几个小的协议包合并成一个大的包来发送(粘包),也可能把一个完整的协议包分拆成几个小的包分开发送(拆包)。这样对方每次接收到的数据都不一定就是一个完整的协议包,需要在代码层再做处理,这就是所谓的粘包跟拆包问题了。

粘包/拆包产生的原因
下面我们通过一个TCP发送数据包的图来详细讲解粘包跟拆包发生的几种情况,假设客户端分别向服务器发送协议包D1、D2,每次服务器接收的字节数是不确定的,如下所示:

  • 第一种情况,服务器分两次读取到了两个独立的协议包,分别是D1和D2,没有粘包和拆包;
  • 第二种情况,服务器一次读取到了两个协议包,D1和D2被合并在一起,发生了粘包;
  • 第三种情况,服务器第一次读取协议包D1的一部分D1_1,第二次读取到D1的剩余部分D1_2和协议包D2的全部,协议包D1读取时被拆成两部分了,发生了拆包;
  • 第四种情况,服务器第一次读取协议包D1的全部和协议包D2的一部分D2_1,第二次读取到协议包D2剩余的部分D2_2,协议包读取时被拆分了,也发生了拆包;
  • 第五种情况,服务器第一次读取协议包D1的全部和协议包D2的一部分D2_1,第二次读取到协议包D2部分D2_2,第三次读取到协议包D2的剩余部分D2_3,也发生了拆包;
如果服务器接收的滑窗比较小,而协议包D1和D2都比较大,那么服务器可能需要接收多次才能把协议包全部接收完,期间就会发生多次的拆包。

通过上面的分析,我们可以知道出现粘包跟拆包的根本原因大于服务器每次接收的字节数是不确定的,如果服务器每次接收的字节数等于我们定义的协议包的字节数,那么就不会发生粘包或者拆包了(假设协议包大小是固定的)。至于服务器为什么接收的字节数不确定,有以下几个原因:
  • 应用程序写入数据的字节大小是随意的,很可能跟套接字发送缓冲区的大小不一样;
  • TCP协议MSS大小造成的TCP分段;
  • IP层数据报长度比链路层的MTU大,从而造成IP分片;

MSS:最大报文段长度的缩写,它表示TCP报文段中的数据字段的最大长度,MSS=TCP报文段长度-TCP首部长度;
MTU:最大传输单元的缩写,链路层对数据帧的长度有一个限制,它的最大值就被称作MTU;

粘包/拆包的解决之道
  • 消息定长,如固定协议包长度是100字节,如果不够,包尾空格补位;
  • 包尾增加换行符或者其它符号进行分割,如FTP协议;
  • 将消息分为消息头和消息体,在消息头固定的位置增加一个字段,表示消息的总长度(或消息的长度),参照TCP协议;
  • 使用更复杂的应用层协议;

版权说明:如无特殊说明,文章均为本站原创,如需转载请注明出处

本文标题:TCP粘包与拆包分析及解决之道

本文地址:http://www.wolfbe.com/detail/201609/379.html

本文标签: 粘包 拆包 tcp

相关文章

感谢您的支持,朗度云将继续前行

扫码打赏,金额随意

温馨提醒:打赏一旦完成,金额无法退还,请谨慎操作!

扫二维码 我要反馈 回到顶部