粘包/半包问题

什么是 TCP 粘包半包?

假设客户端分别发送了两个数据包 D1 和 D2 给服务端, 由于服务端一次读取到的字节
数是不确定的, 故可能存在以下 4 种情况。
(1) 服务端分两次读取到了两个独立的数据包, 分别是 D1 和 D2, 没有粘包和拆包;
(2) 服务端一次接收到了两个数据包, D1 和 D2 粘合在一起, 被称为 TCP 粘包;
(3) 服务端分两次读取到了两个数据包, 第一次读取到了完整的 D1 包和 D2 包的部分
内容, 第二次读取到了 D2 包的剩余内容, 这被称为 TCP 拆包;
(4) 服务端分两次读取到了两个数据包, 第一次读取到了 D1 包的部分内容 D1_1, 第
二次读取到了 D1 包的剩余内容 D1_2 和 D2 包的整包。
如果此时服务端 TCP 接收滑窗非常小, 而数据包 D1 和 D2 比较大, 很有可能会发生第
五种可能, 即服务端分多次才能将 D1 和 D2 包接收完全, 期间发生多次拆包。
TCP 粘包/半包发生的原因
由于 TCP 协议本身的机制(面向连接的可靠地协议-三次握手机制) 客户端与服务器会
维持一个连接(Channel) , 数据在连接不断开的情况下, 可以持续不断地将多个数据包发
往服务器, 但是如果发送的网络数据包太小, 那么他本身会启用 Nagle 算法(可配置是否启
用) 对较小的数据包进行合并(基于此, TCP 的网络延迟要 UDP 的高些) 然后再发送(超
时或者包大小足够) 。 那么这样的话, 服务器在接收到消息(数据流) 的时候就无法区分哪
些数据包是客户端自己分开发送的, 这样产生了粘包; 服务器在接收到数据库后, 放到缓冲
区中, 如果消息没有被及时从缓存区取走, 下次在取数据的时候可能就会出现一次取出多个
数据包的情况, 造成粘包现象
UDP: 本身作为无连接的不可靠的传输协议(适合频繁发送较小的数据包) , 他不会对
数据包进行合并发送(也就没有 Nagle 算法之说了) , 他直接是一端发送什么数据, 直接就
发出去了, 既然他不会对数据合并, 每一个数据包都是完整的(数据+UDP 头+IP 头等等发一
次数据封装一次) 也就没有粘包一说了。
分包产生的原因就简单的多: 可能是 IP 分片传输导致的, 也可能是传输过程中丢失部
分包导致出现的半包, 还有可能就是一个包可能被分成了两次传输, 在取数据的时候, 先取
到了一部分(还可能与接收的缓冲区大小有关系) , 总之就是一个数据包被分成了多次接收。
更具体的原因有三个, 分别如下。
1. 应用程序写入数据的字节大小大于套接字发送缓冲区的大小
2. 进行 MSS 大小的 TCP 分段。 MSS 是最大报文段长度的缩写。 MSS 是 TCP 报文段中的
数据字段的最大长度。 数据字段加上 TCP 首部才等于整个的 TCP 报文段。 所以 MSS 并不是
TCP 报文段的最大长度, 而是: MSS=TCP 报文段长度-TCP 首部长度
3. 以太网的 payload 大于 MTU 进行 IP 分片。 MTU 指: 一种通信协议的某一层上面所能
通过的最大数据包大小。 如果 IP 层有一个数据包要传, 而且数据的长度比链路层的 MTU 大,
那么 IP 层就会进行分片, 把数据包分成托干片, 让每一片都不超过 MTU。 注意, IP 分片可
以发生在原始发送端主机上, 也可以发生在中间路由器上。
解决粘包半包问题
由于底层的 TCP 无法理解上层的业务数据, 所以在底层是无法保证数据包不被拆分和重
组的, 这个问题只能通过上层的应用协议栈设计来解决, 根据业界的主流协议的解决方案,
可以归纳如下。
(1) 在包尾增加分割符, 比如回车换行符进行分割, 例如 FTP 协议;
(2) 消息定长, 例如每个报文的大小为固定长度 200 字节, 如果不够, 空位补空格;
(3) 将消息分为消息头和消息体, 消息头中包含表示消息总长度(或者消息体长度)
的字段, 通常设计思路为消息头的第一个字段使用 int32 来表示消息的总长度, 使用
LengthFieldBasedFrameDecoder, 后面会有详细说明和使用。
 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值