【计算机网络】粘包和拆包

TCP的粘包和拆包问题往往出现在基于TCP协议的通讯中,比如RPC框架、Netty等。如果你的简历中写了类似的技术或者你所面试的公司使用了相关的技术,被问到该面试的几率会非常高。

今天这篇文章就带大家详细了解一下TCP的粘包和拆包以及解决方案。

1 什么是粘包

在学习粘包之前,先纠正一下读音,很多视频教程中将“粘”读作“nián”。经过调研,个人更倾向于读“zhān bāo”。

如果在百度百科上搜索“粘包”,对应的读音便是“zhān bāo”,语义解释为:网络技术术语。指TCP协议中,发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

TCP是面向字节流的协议,就是没有界限的一串数据,本没有“包”的概念,“粘包”和“拆包”一说是为了有助于形象地理解这两种现象。

2 为什么UDP没有粘包

粘包拆包问题在数据链路层、网络层以及传输层都有可能发生。日常的网络应用开发大都在传输层进行,由于UDP有消息保护边界,不会发生粘包拆包问题,因此粘包拆包问题只发生在TCP协议中。

3 粘包拆包发生场景

因为TCP是面向流,没有边界,而操作系统在发送TCP数据时,会通过缓冲区来进行优化,例如缓冲区为1024个字节大小。

如果一次请求发送的数据量比较小,没达到缓冲区大小,TCP则会将多个请求合并为同一个请求进行发送,这就形成了粘包问题。

如果一次请求发送的数据量比较大,超过了缓冲区大小,TCP就会将其拆分为多次发送,这就是拆包。

关于粘包和拆包可以参考下图的几种情况:

上图中演示了以下几种情况:

  • 正常的理想情况,两个包恰好满足TCP缓冲区的大小或达到TCP等待时长,分别发送两个包;
  • 粘包:两个包较小,间隔时间短,发生粘包,合并成一个包发送;
  • 拆包:一个包过大,超过缓存区大小,拆分成两个或多个包发送;
  • 拆包和粘包:Packet1过大,进行了拆包处理,而拆出去的一部分又与Packet2进行粘包处理。

4 常见的解决方案

对于粘包和拆包问题,常见的解决方案有四种:

  • 发送端将每个包都封装成固定的长度,比如100字节大小。如果不足100字节可通过补0或空等进行填充到指定长度;
  • 发送端在每个包的末尾使用固定的分隔符,例如\r\n。如果发生拆包需等待多个包发送过来之后再找到其中的\r\n进行合并;例如,FTP协议;
  • 将消息分为头部和消息体,头部中保存整个消息的长度,只有读取到足够长度的消息之后才算是读到了一个完整的消息;
  • 通过自定义协议进行粘包和拆包的处理。

5 Netty对粘包和拆包问题的处理

Netty对解决粘包和拆包的方案做了抽象,提供了一些解码器(Decoder)来解决粘包和拆包的问题。如:

  • LineBasedFrameDecoder:以行为单位进行数据包的解码;
  • DelimiterBasedFrameDecoder:以特殊的符号作为分隔来进行数据包的解码;
  • FixedLengthFrameDecoder:以固定长度进行数据包的解码;
  • LenghtFieldBasedFrameDecode:适用于消息头包含消息长度的协议(最常用);

基于Netty进行网络读写的程序,可以直接使用这些Decoder来完成数据包的解码。对于高并发、大流量的系统来说,每个数据包都不应该传输多余的数据(所以补齐的方式不可取),LenghtFieldBasedFrameDecode更适合这样的场景。

6 小结

TCP协议粘包拆包问题是因为TCP协议数据传输是基于字节流的,它不包含消息、数据包等概念,需要应用层协议自己设计消息的边界,即消息帧(Message Framing)。如果应用层协议没有使用基于长度或者基于终结符息边界等方式进行处理,则会导致多个消息的粘包和拆包。

虽然很多框架中都有现成的解决方案,比如Netty,但底层的原理我们还是要清楚的,而且还要知道有这么会事,才能更好的结合场景进行使用。

转载:面试题:聊聊TCP的粘包、拆包以及解决方案 - 知乎 (zhihu.com)

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty中的TCP粘包拆包问题是由于底层的TCP协议无法理解上层的业务数据而导致的。为了解决这个问题,Netty提供了几种解决方案。其中,常用的解决方案有四种[1]: 1. 固定长度的拆包器(FixedLengthFrameDecoder):将每个应用层数据包拆分成固定长度的大小。这种拆包器适用于应用层数据包长度固定的情况。 2. 行拆包器(LineBasedFrameDecoder):将每个应用层数据包以换行符作为分隔符进行分割拆分。这种拆包器适用于应用层数据包以换行符作为结束符的情况。 3. 分隔符拆包器(DelimiterBasedFrameDecoder):将每个应用层数据包通过自定义的分隔符进行分割拆分。这种拆包器适用于应用层数据包以特定分隔符作为结束标志的情况。 4. 基于数据包长度的拆包器(LengthFieldBasedFrameDecoder):将应用层数据包的长度作为接收端应用层数据包的拆分依据。根据应用层协议中包含的数据包长度进行拆包。这种拆包器适用于应用层协议中包含数据包长度的情况。 除了使用这些拆包器,还可以根据业界主流协议的解决方案来解决粘包拆包问题[3]: 1. 消息长度固定:累计读取到长度和为定长LEN的报文后,就认为读取到了一个完整的信息。 2. 使用特殊的分隔符:将换行符或其他特殊的分隔符作为消息的结束标志。 3. 在消息头中定义长度字段:通过在消息头中定义长度字段来标识消息的总长度。 综上所述,Netty提供了多种解决方案来解决TCP粘包拆包问题,可以根据具体的业务需求选择合适的解决方案[1][3]。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值