TCP 是个“流”协议,所谓流,就是没有界限的一串数据。大家可以想想河里的流水, 是连成一片的,其间并没有分界线。
假设 Socket 通道中有两个完整的数据包 D1、D2
什么是粘包
第一次读取到了 D1、D2 完整数据包,D1 跟 D2 就粘一起了,确当成是一个数据包处理。
什么是拆包
第一次读取到了完整的 D1 包和 D2 包的部分内容,第二次读取到了 D2 包的剩余内容,导致 D2 数据包不完整。
解决方案
1:报文限定长度
设定(发送/响应)报文长度,如果(发送/响应)报文长度不够,空位补空格。
优点: 简单,快捷,方便。
缺点: 长度设置大了,浪费内存。设置小了,又怕不够。
2:设定分隔符
在报文结尾设置分隔符,比如 \r\n 或者一些特殊的字符。
优点: 简单,快捷,方便。
缺点:在读取报文的时候,不会是 1 个 1 个字节去读取,所以需要自己检索特殊分隔 符位置。而且有可能会读取到下一个报文内容,所以也需要将读取到的报文进行缓存。
例如:第一次读取:[1,2,3,4,\r,\n,7,8,9],
第二次读取:[10,11,12,\r,\n,13,14,15]
[1,2,3,4]是一个完整的报文,[7,8,9,10,11,12]是一个完整报文。
3:将报文分成【消息头,消息体】
设定固定的消息头长度,消息头中描述消息体的长度。
例如:
在读取报文的时候,先将固定长度的消息头读取,获取的消息体长度,再读取 出消息体报文。
优点: 有效解决粘包/拆包问题。