拼多多面试:Netty如何解决粘包问题?

简介: 粘包和拆包问题也叫做粘包和半包问题,**它是指在数据传输时,接收方未能正常读取到一条完整数据的情况(只读取了部分数据,或多读取到了另一条数据的情况)就叫做粘包或拆包问题。**从严格意义上来说,粘包问题和拆包问题属于两个不同的问题,接下来我们分别来看。## 1.粘包问题粘包问题是指在网络通信中,发送方连续发送的多个小数据包被接收方一次性接收的现象。这可能是因为底层传输层协议(如 TCP)会将多个小数据包合并成一个大的数据块进行传输,导致接收方在接收数据时一次性接收了多个数据包,造成粘连。例如以下案例,正常情况下客户端发送了两条消息,分别为“ABC”和“DEF”,那么接收端也应该收到两

粘包和拆包问题也叫做粘包和半包问题,它是指在数据传输时,接收方未能正常读取到一条完整数据的情况(只读取了部分数据,或多读取到了另一条数据的情况)就叫做粘包或拆包问题。

从严格意义上来说,粘包问题和拆包问题属于两个不同的问题,接下来我们分别来看。

1.粘包问题

粘包问题是指在网络通信中,发送方连续发送的多个小数据包被接收方一次性接收的现象。这可能是因为底层传输层协议(如 TCP)会将多个小数据包合并成一个大的数据块进行传输,导致接收方在接收数据时一次性接收了多个数据包,造成粘连。

例如以下案例,正常情况下客户端发送了两条消息,分别为“ABC”和“DEF”,那么接收端也应该收到两条消息“ABC”和“DEF”才对,但是接收端却收到了“ABCD”这样的消息,这种情况就叫做粘包,如下图所示:
image.png

2.拆包/半包问题

拆包问题是指发送方发送的一个大数据包被接收方拆分成多个小数据包进行接收的现象。这可能是因为底层传输层协议(如 TCP)将一个大数据包拆分成多个小的数据块进行传输,导致接收方在接收数据时分别接收了多个小数据包,造成拆开。

例如以下案例,客户端发送了一条消息“ABC”,而接收端却收到了“AB”和“C”两条信息,这种情况就叫做半包,如下图所示:
image.png

PS:大部分情况下我们都把粘包问题和拆包问题看成同一个问题,所以下文就用粘包问题来替代粘包和拆包问题。

3.为什么会有粘包问题?

粘包问题通常发生在 TCP/IP 协议中,因为 TCP 是面向连接的传输协议,它是以“流”的形式传输数据的,而“流”数据是没有明确的开始和结尾边界的,所以就会出现粘包问题

4.常见解决方案

粘包问题的常见解决方案有以下 3 种:

  1. 固定大小方法:发送方和接收方固定发送数据大小,当字符长度不够时用空字符弥补,有了固定大小之后就知道每条消息的具体边界了,这样就没有粘包的问题了。
  2. 自定义数据协议(定义数据长度):在 TCP 协议的基础上封装一层自定义数据协议,在自定义数据协议中,包含数据头(存储数据的大小)和 数据的具体内容,这样服务端得到数据之后,通过解析数据头就可以知道数据的具体长度了,也就没有粘包的问题了。
  3. 特殊分割符:以特殊的字符结尾,比如以“\n”结尾,这样我们就知道数据的具体边界了,从而避免了粘包问题。

以上三种方案中,第一种固定大小的方法可能会造成网络流量的浪费,以及传输性能慢的问题;第二种解决方案实现难度大,且不利于维护,所以比较推荐的是第三种方案,使用特殊分隔符来区分消息的边界,从而避免粘包问题。

5.Netty解决方案

Netty 解决方案也延续了上面的常见解决方案,它的解决方案有以下几个:

  1. 使用定长解码器(FixedLengthFrameDecoder):每个数据包都拥有固定的长度,接收端根据固定长度对数据进行切分,从而解决了粘包问题。
  2. 使用行分隔符解码器(LineBasedFrameDecoder):以行为单位进行数据包的解码,从而解决粘包问题。
  3. 使用分隔符解码器(DelimiterBasedFrameDecoder):使用特定的分隔符来标识消息边界,这样接收端可以根据分隔符正确切分消息。
  4. 使用长度字段解码器(LengthFieldBasedFrameDecoder):在消息头部加入表示消息长度的字段,接收端根据长度字段来确定消息的边界,而从解决粘包问题。

    PS:在 Netty 中,解码器(Decoder)起着非常重要的作用。解码器主要负责将从网络中接收到的原始字节流数据转换为应用程序能够理解的 Java 对象或消息格式。使用解码器可以解决粘包和拆包问题、协议转换问题、消息编码(如文本转换为字节流)等问题。

这些解码器的使用如下。

5.1 定长解码器

定长解码器(FixedLengthFrameDecoder)使用示例如下:

ChannelPipeline pipeline = ch.pipeline();
// 假设每条消息长度为 5
pipeline.addLast(new FixedLengthFrameDecoder(5)); 
pipeline.addLast(new StringDecoder());
pipeline.addLast(new YourBusinessLogicHandler());

5.2 行分隔符解码器

行分隔符解码器(LineBasedFrameDecoder)使用示例如下:

ChannelPipeline pipeline = ch.pipeline();
// 设置行分隔符解码器最大(帧)长度为 8192 字节
pipeline.addLast(new LineBasedFrameDecoder(8192)); 
pipeline.addLast(new StringDecoder()); // 添加字符串解码器
pipeline.addLast(new SimpleChannelInboundHandler<String>() {
   
   
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
   
   
        System.out.println("接收到消息:" + msg);
    }
});

5.3 分隔符解码器

分隔符解码器(DelimiterBasedFrameDecoder)使用示例如下:

ChannelPipeline pipeline = ch.pipeline();
// 使用 \r\n 来进行分隔
ByteBuf delimiter = Unpooled.copiedBuffer("\r\n".getBytes());
pipeline.addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new YourBusinessLogicHandler());

5.4 长度字段解码器

长度字段解码器(LengthFieldBasedFrameDecoder)使用示例如下:

ChannelPipeline pipeline = ch.pipeline();
// 设置最大帧长度为 1024 字节,长度字段位于第 0 个字节,长度字段占用 4 个字节
pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new LengthFieldServerHandler());

课后思考

除了定长解码器、行分隔符解码器、分隔符解码器、长度字段解码器之外,Netty 还有其他解决粘包问题的解决方案吗?如何自定义解码器?

本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

相关文章
|
4月前
|
编解码 网络协议 开发者
Netty运行原理问题之NettyTCP的粘包和拆包的问题如何解决
Netty运行原理问题之NettyTCP的粘包和拆包的问题如何解决
|
4月前
|
存储 缓存 算法
这些年背过的面试题——Netty篇
本文是技术人面试系列Netty篇,面试中关于Netty都需要了解哪些基础?一文带你详细了解,欢迎收藏!
|
4月前
|
移动开发 网络协议 算法
(十)Netty进阶篇:漫谈网络粘包、半包问题、解码器与长连接、心跳机制实战
在前面关于《Netty入门篇》的文章中,咱们已经初步对Netty这个著名的网络框架有了认知,本章的目的则是承接上文,再对Netty中的一些进阶知识进行阐述,毕竟前面的内容中,仅阐述了一些Netty的核心组件,想要真正掌握Netty框架,对于它我们应该具备更为全面的认知。
235 2
|
5月前
|
Linux 编译器 Shell
拼多多面试 Linux下一个应用程序开始执行到main被调用之间经历了什么?
在Linux中,程序启动到`main`调用涉及加载器、内核、动态链接器和C运行时。`execve`系统调用加载ELF文件,内核创建进程,加载段,设置栈和调用动态链接器。动态链接器解析符号,重定位,执行初始化。C运行时初始化堆栈,调用`main`。从`_start`到`main`的流程包括环境设置和函数调用。
73 0
|
7月前
|
消息中间件 监控 Java
滴滴面试:谈谈你对Netty线程模型的理解?
Netty 线程模型是指 Netty 框架为了提供高性能、高并发的网络通信,而设计的管理和利用线程的策略和机制。 **Netty 线程模型被称为 Reactor(响应式)模型/模式,它是基于 NIO 多路复用模型的一种升级,它的核心思想是将 IO 事件和业务处理进行分离,使用一个或多个线程来执行任务的一种机制。** ## 1.**Reactor三大组件** Reactor 包含以下三大组件: ![image.png](https://cdn.nlark.com/yuque/0/2024/png/92791/1717079218890-89000a00-48bc-4a1a-b87e-e1b6
71 2
|
6月前
|
网络协议
netty粘包问题分析
netty粘包问题分析
44 0
|
7月前
|
设计模式 前端开发 网络协议
面试官:说说Netty的核心组件?
Netty 核心组件是指 Netty 在执行过程中所涉及到的重要概念,这些核心组件共同组成了 Netty 框架,使 Netty 框架能够正常的运行。 Netty 核心组件包含以下内容: 1. 启动器 Bootstrap/ServerBootstrap 2. 事件循环器 EventLoopGroup/EventLoop 3. 通道 Channel 4. 通道处理器 ChannelHandler 5. 通道管道 ChannelPipeline 这些组件的交互流程如下: ![image.png](https://cdn.nlark.com/yuque/0/2024/png/92791/1716
47 0
面试官:说说Netty的核心组件?
|
6月前
|
Java
Netty传输object并解决粘包拆包问题
Netty传输object并解决粘包拆包问题
52 0
|
6月前
|
Java
Netty中粘包拆包问题解决探讨
Netty中粘包拆包问题解决探讨
41 0
|
7月前
|
存储 前端开发 JavaScript
web前端 第一阶段面试题(1),2024年最新拼多多前端社招面试
web前端 第一阶段面试题(1),2024年最新拼多多前端社招面试