客户端和服务器之间要进行基于 TCP 的套接字通信
- 通信过程中客户端会每次会不定期给服务器发送一个不定长度的有特定含义的字符串。
- 通信的服务器端每次都需要接收到客户端这个不定长度的字符串,并对其进行解析
根据上面的描述,服务器在接收数据的时候有如下几种情况:
- 一次接收到了客户端发送过来的一个完整的数据包
- 一次接收到了客户端发送过来的 N 个数据包,由于每个包的长度不定,无法将各个数据包拆开
- 一次接收到了一个或者 N 个数据包 + 下一个数据包的一部分,还是很悲剧,无法将数据包拆开
- 一次收到了半个数据包,下一次接收数据的时候收到了剩下的一部分 + 下个数据包的一部分,更悲剧,头大了
- 另外,还有一些不可抗拒的因素:比如客户端和服务器端的网速不一样,发送和接收的数据量也会不一致
对于以上描述的现象很多时候我们将其称之为 TCP的粘包问题,但是这种叫法不太对的,本身 TCP 就是面向连接的流式传输协议,特性如此,我们却说是 TCP 这个协议出了问题,这只能说是使用者的无知。多个数据包粘连到一起无法拆分是我们的需求过于复杂造成的,是程序猿的问题而不是协议的问题,TCP 协议表示这锅它不想背。
几种解决方案:
- 使用标准的应用层协议(比如:http、https)来封装要传输的不定长的数据包
- 在每条数据的尾部添加特殊字符,如果遇到特殊字符,代表当条数据接收完毕了
有缺陷:效率低,需要一个字节一个字节接收,接收一个字节判断一次,判断是不是那个特殊字符串
3.在发送数据块之前,在数据块最前边添加一个固定大小的数据头,这时候数据由两部分组成:数据头 + 数据块
数据头:存储当前数据包的总字节数,接收端先接收数据头,然后在根据数据头接收对应大小的字节
数据块:当前数据包的内容
解决方案:
如果使用 TCP 进行套接字通信,如果发送的数据包粘连到一起导致接收端无法解析,我们通常使用添加包头的方式轻松地解决掉这个问题。关于数据包的包头大小可以根据自己的实际需求进行设定,这里没有啥特殊需求,因此规定包头的固定大小为4个字节,用于存储当前数据块的总字节数。
https://subingwen.cn/linux/tcp-data-package/#1-%E8%83%8C%E9%94%85%E4%BE%A0TCP