TCP协议是可靠的,数据包一定会到达(99.9%的情况下),而且是按顺序到达。
TCP是“流”协议,所谓“流”协议,就是没有界限,没有分割的一串数据。TCP会根据缓冲区实际情况进行划分,一个完整的包可能会拆分成多个包进行发送,也有可能把多个小包封装成一个大的数据包发送,这就是TCP粘包/拆包。
发生原因
- 应用程序写入的数据大于套接字缓冲区大小,这将会发生拆包。
- 应用程序写入数据小于套接字缓冲区大小,网卡将应用多次写入的数据发送到网络上,这将会发生粘包。
- 接收方法不及时读取套接字缓冲区数据,这将发生粘包。
解决方案
无论拆包还是粘包本质问题都是无法区分包界限,解决包界限的问题主要有以下几种方式:
- 消息数据的定长,比如定长100字节,不足补空格,接收方收到后解析100字节数据即为完整数据。但这样的做的缺点是浪费了部分存储空间和带宽。
- 消息数据使用特定分割符区分界限,比如使用换号符号做分割。
- 把消息数据分成消息头和消息体,消息头带消息的长度,接收方收到后根据消息头中的长度解析数据。
在实际开发中很多网络框架对TCP拆包粘包问题的解决做了很多支持,比如netty中LineBasedFrameDecoder解析器就是利用换号符号做分割。
参考文档
【1】浅谈TCP拆包粘包问题
【2】TCP粘包/拆包
【3】TCP粘包,拆包及解决方法