怎么解决TCP网络传输“粘包”问题
1
TCP粘包是指发送方发送的多个数据包到接收方后粘连在一起,导致数据包不能完整的提现发送的数据。
TCP协议
TCP是一个面向连接的传输层协议,不属于ISO制定的协议集。TCP协议在商业界和工业界的成功应用,使它成为事实上的网络标准,广泛应用于各种网络主机间的通信。
TCP目标是为用户提供可靠的端到端连接,保证信息有序无误的传输。TCP为确保可靠性采用了数据编号、校验和计算、数据确认等一系列措施。
2
回答问题之前,先来纠正题主的一个错误概念,TCP是一种基于字节流的协议,根本不存在所谓的“包”,更不必说粘包。我想题主应该想问:TCP传输协议下,应用层数据发送和接收问题。
官方文档说的已经很清楚了,send和recv的返回值表示成功发送/接收的字节数。
-
man send
-
man recv
3
当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API)。TCP/IP传输层有两个并列的协议:TCP和UDP。其中TCP(transport control protocol,传输控制协议)是面向连接的,提供高可靠性服务。UDP(user datagram protocol,用户数据报协议)是无连接的,提供高效率服务。在实际工程应用中,对可靠性和效率的选择取决于应用的环境和需求。一般情况下,普通数据的网络传输采用高效率的udp,重要数据的网络传输采用高可靠性的TCP。
在应用开发过程中,笔者发现基于TCP网络传输的应用程序有时会出现粘包现象(即发送方发送的若干包数据到接收方接收时粘成一包)。针对这种情况,我们进行了专题研究与实验。本文重点分析了TCP网络粘包问题,并结合实验结果提出了解决该问题的对策和方法,供有关工程技术人员参考。
4
以上图的协议结构,来举个粟子:
1. 我们收到完整的一个协议串为hex码为:
232301314731424c35325037545231313535323001000000
2.对应的拆解一下,各项数值为
5
设计方案一:定长发送
在进行数据发送时采用固定长度的设计,也就是无论多大数据发送都分包为固定长度(为便于描述,此处定长为记为LEN),也就是发送端在发送数据时都以LEN为长度进行分包。这样接收方都以固定的LEN进行接收,如此一来发送和接收就能一一对应了。分包的时候不一定能完整的恰好分成多个完整的LEN的包,最后一个包一般都会小于LEN,这时候最后一个包可以在不足的部分填充空白字节。
当然,这种方法会有缺陷。1.最后一个包的不足长度被填充为空白部分,也即无效字节序。那么接收方可能难以辨别这无效的部分,它本身就是为了补位的,并无实际含义。这就为接收端处理其含义带来了麻烦。当然也有解决办法,可以通过增添标志位的方法来弥补,即在每一个数据包的最前面增加一个定长的报头,然后将该数据包的末尾标记一并发送。接收方根据这个标记确认无效字节序列,从而实现数据的完整接收。2.在发送包长度随机分布的情况下,会造成带宽浪费。比如发送长度可能为 1,100,1000,4000字节等等,则都需要按照定长最大值即4000来发送,数据包小于4000字节的其他包也会被填充至4000,造成网络负载的无效浪费。
综上,此方案适在发送数据包长度较为稳定(趋于某一固定值)的情况下有较好的效果。
设计方案二:尾部标记序列
6
看到这个问题让我想起之前做过的一个关于粘包问题的测试,分享一下我的经验。
发生粘包问题首先要分析粘包的原因,然后对症下药
粘性包装问题的分析及对策
发生粘连现象的原因很多,可能是由发送者或接收者引起的。
由发送方引起的粘性数据包由TCP协议本身引起。为了提高传输效率,发送方经常在发送数据包之前收集足够的数据。如果连续几次发送的数据很小,通常TCP会将数据合成为一个数据包,然后根据优化算法将其发送出去,以便接收方接收粘性数据包。
7
要靠消息封装来解决,约定定长的消息头,消息头内标明消息数据长度。接收端通过消息缓存和消息头来完成消息提取。