IO之NETTY(更新中)

本文深入讲解Netty框架的核心概念和技术细节,包括反应器模式、Channel通道管理、ByteBuf缓冲区优化、序列化处理等,帮助读者理解Netty如何高效处理网络通信。

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

        近期在做充电桩项目,桩设备与系统之间的连接方式,一种是基于Socket协议,一种是Mqtt这种消息中间件的,当初为了快,直接用socket搞了个异步处理接收桩,在少量问题可能对系统不会有太大问题

可随着桩数量增加,就应该用更高效的框架了,比如netty。继IO整理之后,整理一篇关于Netty的文章。

      了解更多JAVA后台知识整理:JAVA后台系列目录

      1. Netty中的反应器模式实现

            反应器模式(Reactor模式)的应用场景:Nginx、Redis、Netty

            组成:Reactor反应器线程:负责响应IO事件,并且分发到Handlers处理器

                       Handlers处理器:非阻塞的执行业务处理逻辑

            Socket 对于每一个新的网络连接都分配给一个线程,对于大量连接时这个是致命的缺陷

            在反应器模式中,需要进行attach和attachment结合使用:在选择键注册完成之后,调用attach方法,将Handler实例绑定到选择键;

            当IO事件发生时,调用attachment方法,可以从选择键取出Handler实例,将事件分发到Handler处理器中,完成业务处理

            Netty对于Channel进行了封装,底层依赖了NIO的成员SelectableChannel

           

 

            Netty中反应器的组件:NioEventLoopGroup 相当于NIO中的Selector和Thread的结合,可以拥有线程监听的两种功效

            

           

            Handler: 出站和入站两种类型

            

            Netty的Pipeline通道处理流水线

                   ChannelPipeline:一条双向链表,类似水流一样的流动,从一边流向另一边,可以自然停止和主动停止两种方式,并且双向流动

      2. Bootstrap引导类

                

                父子通道的感念:NioServerSocketChannel(服务器端)、NioSocketChannel(客户端)

                EventLoopGroup轮询组:就是两个监听Boss和worker的关系

                启动案例代码:

         

public class NettyDiscardServer {
    private final int serverPort;
    ServerBootstrap b = new ServerBootstrap();

    public NettyDiscardServer(int port) {
        this.serverPort = port;
    }

    public void runServer() {
        //创建reactor 线程组
        EventLoopGroup bossLoopGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerLoopGroup = new NioEventLoopGroup();

        try {
            //1 设置reactor 线程组
            b.group(bossLoopGroup, workerLoopGroup);
            //2 设置nio类型的channel
            b.channel(NioServerSocketChannel.class);
            //3 设置监听端口
            b.localAddress(serverPort);
            //4 设置通道的参数
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            b.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            //5 装配子通道流水线
            b.childHandler(new ChannelInitializer<SocketChannel>() {
                //有连接到达时会创建一个channel
                protected void initChannel(SocketChannel ch) throws Exception {
                    // pipeline管理子通道channel中的Handler
                    // 向子channel流水线添加一个handler处理器
                    ch.pipeline().addLast(new NettyDiscardHandler());
                }
            });
            // 6 开始绑定server
            // 通过调用sync同步方法阻塞直到绑定成功
            ChannelFuture channelFuture = b.bind().sync();
            Logger.info(" 服务器启动成功,监听端口: " + channelFuture.channel().localAddress());
            // 7 等待通道关闭的异步任务结束
            // 服务监听通道会一直等待通道关闭的异步任务结束
            ChannelFuture closeFuture = channelFuture.channel().closeFuture();
            closeFuture.sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 8 优雅关闭EventLoopGroup,
            // 释放掉所有资源包括创建的线程
            workerLoopGroup.shutdownGracefully();
            bossLoopGroup.shutdownGracefully();
        }

    }

       ChannelOption通道选项:

              SO_RCVBUF和SO_SNDBUF、TCP_NODELAY、SO_KEEPALIVE、SO_REUSEADDR、SO_LINGER、SO_BACKLOG、SO_BROADCAST

      3. Channel通道

               主要方法说明:

                 1.  ChannelFuture connect(SocketAddress address) 连接远程服务器,客户端使用

                 2.  ChannelFuture bind(SocketAddress address)服务器端监听使用

                 3.  ChannelFuture close() 关闭连接

                 4.  Channel read() 读取数据入站处理

                 5.  ChannelFuture write(Object o)启用出站处理

                 6.  Channel flush() 缓冲区写到对端

              EmbeddedChannel仅仅是模拟入站与出站的操作,包含writeInbound和writeOutbound方法,测试时很好用的一个工具

      4. Handler业务处理器

             入站处理器主要方法

              

           执行流程:handlerAdded()→ channelRegistered() →channelActive() →数据传输的入站回调→ channelInactive()→ channelUnregistered() →handlerRemoved()

            出站处理器主要方法

                 

             ChannelInitializer通道初始化处理器,输入入站拿到新连接通道作为实际参数,往它的流水线中装配Handler业务处理器

      5. PipeLine通道流水线

              流水线入站顺序调用,出站逆序调用,就好比一列火车,每节车厢在进入火车站,然后火车掉头,从另一个反向出站

              Channel、Handler、ChannelHandlerContext三者的关系:Channel通道拥有一条ChannelPipeline通道流水线,
              每一个流水线节点为一个ChannelHandlerContext上下文对象,每一个上下文中包裹了一个ChannelHandler通道处理器。

             HeadContext与TailContext头尾上下文

             

             

      6. ByteBuf缓冲区

                 ByteBuf缓冲区组件来替代Java NIO的ByteBuffer缓冲区组件

                 优势:

                         Pooling (池化,这点减少了内存复制和GC,提升了效率);复合缓冲区类型,支持零复制;不需要调用flip()方法去切换读/写模式;可扩展性好
                        可以自定义缓冲区类型;读取和写入索引分开;方法的链式调用;  可以进行引用计数,方便重复使用     

                  四个组成

                        第一个部分是已用字节,表示已经使用完的废弃的无效字节;

                        第二部分是可读字节,这部分数据是ByteBuf保存的有效数据,从ByteBuf中读取的数据都来自这一部分;

                        第三部分是可写字节,写入到ByteBuf的数据都会写到这一部分中;

                        第四部分是可扩容字节,表示的是该ByteBuf最多还能扩容的大小。

                    三个属性

                         readerIndex(读指针)

                         writerIndex(写指针)

                         maxCapacity(最大容量)

                       三组方法

                          容量方法

                          写入方法

                          读取系列

                     ByteBuf的引用计数

                      Allocator分配器PoolByteBufAllocator和UnpooledByteBufAllocator,在大量连接情况下,池化分配器可以减少内存的持续消耗

                     缓冲区的类型

                           

                     
   
      7. 核心组件 编码器 和解码器

                      ByteToMessageDecoder 抽象类,在设计上使用了模板模式,decode抽象方法

                      ByteToMessageCodec抽象类上的encode方法

      8. 粘包、拆包统称半包问题

                  什么是半包问题:在数据发送端和接收到结果不一致

                  半包问题产生的原因:主要是读取操作系统缓冲区大小限制产生,读取多了就粘包了,读取少了就半包了

                  netty如何解决该问题的:

                       (1)可以自定义解码器分包器:基于ByteToMessageDecoder或者ReplayingDecoder,定义自己的用户缓冲区分包器。

                        (2)使用Netty内置的解码器。如可以使用Netty内置的LengthFieldBasedFrameDecoder自定义长度数据包解码器,对用户缓冲区ByteBuf进行正确的分包。

      9. 序列化和反序列化 JSON和Protobuf

       了解更多JAVA后台知识整理:JAVA后台系列目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值