NETTY学习之粘包、半包

本文深入探讨Netty中粘包与半包问题的成因及解决方案,讲解了固定长度、分隔符和长度字段等常见解码方法,并通过实例代码展示了如何使用ByteToMessageDecoder实现自定义解码器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

netty学习的第一篇文章,讲讲内容是啥。最近在极客时间上学netty相关的课,老师上课方式很有问题,每节课先抛出几个问题,在之后的内容中解答这几个问题。而我的话,在看完课之后,再拿着问题,自己解答一遍,这样学习的效率很不错。所以接下来的几篇文章就都是我的学习总结了。第一篇是粘包、半包。

在这里插入图片描述

粘包:一个包里发了多个数据

原因:
1.写入的数据<缓冲区大小(缓冲区没满,就不发)
2.接收方从缓冲区读取的速度太慢

半包:一个包里只有半条数据

原因:
1。写入的数据>缓冲区大小
2.写入的数据大于协议的MTU(最大传输单元),必须拆包

解决粘包和半包的常用方法:

1.固定长度
2.设置分隔符
3.固定长度字段存内容的长度信息(和现在的协议里很像,先给个长度,然后根据长度取截取)

在这里插入图片描述

粘包、半包的解决方式:

1.解码核心工作流程
先说:
维护一个数据积累器,根据不同的解码方式,进行解码

* For example here is an implementation which reads all readable bytes from
* the input {@link ByteBuf} and create a new {@link ByteBuf}.
*
* <pre>
*     public class SquareDecoder extends {@link ByteToMessageDecoder} {
*         {@code @Override}
*         public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, List&lt;Object&gt; out)
*                 throws {@link Exception} {
*             out.add(in.readBytes(in.readableBytes()));
*         }
*     }
* </pre>

通过创建一个decoder继承byteToMessageDecoder

final ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap
        // 组装 NioEventLoopGroup
        .group(bossGroup, workerGroup)
        // 设置channel类型为 NIO 类型
        .channel(NioServerSocketChannel.class)
        // 设置连接配置参数 服务端可连接队列数,对应 TCP/IP 协议 listen 函数中 backlog 参数
        .option(ChannelOption.SO_BACKLOG, 1024)
        // 长连接
        .childOption(ChannelOption.SO_KEEPALIVE, true)
        // 立即写出
        .childOption(ChannelOption.TCP_NODELAY, true)
        // 配置入站、出站事件handler
        .handler(new LoggingHandler(LogLevel.DEBUG))
        .childHandler(gbt32960ChannelInitializer);

先创建serverBootstrap
然后加载childHandler

GBT32960ChannelInitializer extends ChannelInitializer<NioSocketChannel> 

 @Override
    protected void initChannel(NioSocketChannel nioSocketChannel) {
        ChannelPipeline pipeline = nioSocketChannel.pipeline();
        // 心跳检测
        pipeline.addLast("idleStateHandler",
                new IdleStateHandler(readTimeOut, 0, 0, TimeUnit.MINUTES));
        // 分隔符解码器配置 0x23 0x23
//        pipeline.addLast(new DelimiterBasedFrameDecoder(
//                1100, Unpooled.copiedBuffer(new byte[]{DELIMITER_GBT32960_23, DELIMITER_GBT32960_23})));
        pipeline.addLast(new GBT32960BaseDecoder());
        pipeline.addLast(new GBT32960Decoder());
        pipeline.addLast(new GBT32960Encoder());
        pipeline.addLast(businessGroup, gbt32960ClientRealDataMsgHandler);
        pipeline.addLast(businessGroup, gbt32960ClientLoginMsgHandler);
        pipeline.addLast(businessGroup, gbt32960ClientLogoutMsgHandler);
        pipeline.addLast(businessGroup, gbt32960DataPacketHandler);
    }

pipeLine里面添加decoder,继承byteToMessageDecoder,重写其decode方法。
GBT32960BaseDecoder extends ByteToMessageDecoder {

在这里插入图片描述

如果要用默认的decoder的话,直接
pipeline.addLast(new FixedLengthFrameDecoder());

提供几个粘包半包的解决方式。上面有一堆提供的。(这里部分是目前项目中根据业务自己创建的decode方法)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值