Socket 粘包分包的原因及解决办法
该文章部分引用来自:https://blog.csdn.net/double2hao/article/details/83211334
原因
socket发生粘包分包实际上是在TCP传输协议对数据的优化,TCP是“流”协议,传输的过程就像流水一样没有边界,没有界限,而实际上我们只需要取出我们发送的部分即可;这里说明下UDP是"数据包"协议,所以在UDP中不存在粘包分包的情况。
为什么会分包?
在传输过程中,TCP为了保护网络(也称为流量控制),并不是接收到什么就传递什么,而是根据一系列的限制决定发送多少数据出去,这些限制有:用户缓冲区(接收发送缓冲区)、TCP底层缓冲区(各系统下表现会不同)、MTU(最大传输单元,属于数据链路层)等等,想进一步探究参考:
- https://www.cnblogs.com/silyvin/p/11996349.html
- https://www.zhihu.com/question/48454744
概念
粘包:
当发送的字节数据包比较小且频繁发送时,Socket内部会将字节数据进行粘包处理,既将频繁发送的小字节数据打包成 一个整包进行发送,降低内存的消耗。
分包:
当发送的字节数据包比较大时,Socket内部会将发送的字节数据进行分包处理,降低内存和性能的消耗。
例子解释
当前发送方发送了两个包,两个包的内容如下:
123456789
ABCDEFGH
我们希望接收方的情况是:收到两个包,第一个包为:123456789,第二个包为:ABCDEFGH。但是在粘包和分包出现的情况就达不到预期情况。
粘包情况
两个包在很短的时间间隔内发送,比如在0.1秒内发送了这两个包,如果包长度足够的话,那么接收方只会接收到一个包,如下:
123456789ABCDEFGH
分包情况
假设包的长度最长设置为5字节(较极端的假设,一般长度设置为1000到1500之间),那么在没有粘包的情况下,接收方就会收到4个包,如下:
12345
6789
ABCDE
FGH
如何处理粘包分包?
在数据层面处理:
- 约定结束符,遇到结束符时分割数据。
- 发送数据时约定数据长度,获取数据时先接到长度,然后根据长度分割数据。
- 发送数据末尾拼接换行符,使用
BufferedReader
的rd.readLine()
,原理同上。
技术选型:
- 使用成熟的socket框架,很多框架会帮忙处理合包的操作。
- 使用WebSocket,WebSocket是一个
message-based
的协议,它可以自动将数据分片,并且自动将分片的数据组装。