首页 > 其他分享 >拼多多面试:Netty如何解决粘包问题?

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

时间:2024-06-03 15:10:48浏览次数:15  
标签:Netty pipeline addLast 粘包 面试 解码器 分隔符 new

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

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

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、设计模式、消息队列等模块。

标签:Netty,pipeline,addLast,粘包,面试,解码器,分隔符,new
From: https://www.cnblogs.com/vipstone/p/18228941

相关文章

  • Hbase 面试题(六)
    1.简述下HBASE中Split机制?HBase中的Split机制是指将现有的HBase表的Region进行分割的过程。这个过程是HBase自动管理Region的一部分,目的是为了在数据量增长时保持系统的可扩展性和性能。以下是Split机制的关键点:Region定义:在HBase中,表的数据按行键范围分割成多个Regio......
  • Hbase 面试题(五)
    1.简述什么是WAL(WriteAheadLog)预写日志?WAL(WriteAheadLog),即预写日志,是HBase中用于保证数据持久性和一致性的关键机制。以下是WAL的简要概述:目的:WAL的主要目的是在数据实际写入到MemStore之前,先将其记录到一个日志中。这样即使在系统崩溃或故障的情况下,也能够从日......
  • 【信息化人员必备知识&面试宝典】一次完整的HTTP请求是怎样的?
    【信息化人员必备知识&面试宝典】一次完整的HTTP请求是怎样的?HTTP请求基础什么是HTTP?请求与响应模型一次完整的HTTP请求流程步骤一:建立TCP连接步骤二:发送HTTP请求步骤三:服务器处理请求步骤四:发送HTTP响应步骤五:关闭连接或持续连接实战代码示例案例一:使用Python发起GET......
  • 外企测试工程师面试问题精选
    在外企面试测试工程师职位时,通常会遇到技术性和行为性的问题。以下是一些可能会遇到的面试题示例:技术性问题软件测试基础解释黑盒测试和白盒测试的区别。什么是回归测试?为什么需要进行回归测试?描述单元测试、集成测试、系统测试和验收测试之间的区别。测试工具和技术你使......
  • ShardingSphere面试题及参考答案(3万字长文)
    目录什么是ShardingSphere?ShardingSphere的主要组件有哪些?ShardingSphere支持哪些数据库?......
  • Go高阶16,面试官问我go逃逸场景有哪些,我???
    「逃逸分析」就是程序运行时内存的分配位置(栈或堆),是由编辑器来确定的,而非开发者。什么是栈栈只允许从线性表的同一端放入和取出数据,按照后进先出(LIFO,LastInFirstOut)的顺序,如下图:什么是堆对于堆在内存中的分配,我们可以类比成一个房间,分配内存时,需要找一块足够装下家具......
  • 持续总结中!2024年面试必问 20 道 Kafka面试题(三)
    上一篇地址:持续总结中!2024年面试必问20道Kafka面试题(二)-CSDN博客五、Kafka的ISR(In-SyncReplica)是什么?Kafka的ISR(In-SyncReplicas)是Kafka中用于维护数据一致性和高可用性的关键概念之一。ISR列表包含了一个领导者副本(Leader)和与之保持完全同步的追随者副本(Follower......
  • 程序分享--常见算法/编程面试题:删除有序数组中的重复项 II
    关注我,持续分享逻辑思维&管理思维&面试题;可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导;有意找工作的同学,请参考博主的原创:《面试官心得--面试前应该如何准备》,《面试官心得--面试时如何进行自我介绍》, 《做好面试准备,迎接2024金三银四》。或关注博主免费专栏【程序......
  • 赶紧收藏!2024 年最常见 20道 Kafka面试题(二)
    上一篇地址:赶紧收藏!2024年最常见20道Kafka面试题(一)-CSDN博客三、Kafka的设计架构是什么?Kafka的设计架构是分布式和可扩展的,旨在处理高吞吐量的数据流。以下是Kafka设计架构的关键组成部分及其功能:Producer(生产者):生产者是向Kafka集群发送消息的客户端。它们负责创建消息......
  • 面试官:说一说如何优雅的关闭线程池,我:shutdownNow,面试官:粗鲁!
    写在开头面试官:“小伙子,线程池使用过吗,来聊一聊它吧!”我:“好的,然后巴拉巴拉一顿输出之前看过的build哥线程池十八问…”面试官满意的点了点头,紧接着问道:“那你知道如何优雅的关闭线程池吗?”我:“知道知道,直接调用shutdownNow()方法就好了呀!”面试官脸色一变,微怒道:“粗......