从Java NIO到Netty(五)

 2023-01-28
原文作者:一棵小芹菜 原文地址:https://juejin.cn/post/6968644430060322846

Netty 组件介绍

因为Netty被用于架构或者中间件底层通讯,所以平时我并没有直接基于Netty进行编程过,所以先大概读一下用户手册,发现用户手册Netty对基本概念两三句话概括了之,所以自己先研究了下Netty核心组件的基本概念,之后再去读源码。

从抛弃服务代码讲起

接下来先上用户手册中的抛弃服务(只接收数据不做出任何响应)代码,这两个类基本涵盖了netty的基本使用,我会在代码中注释,然后开始对其核心组件进行讲解,如果大家对哪个组件不理解需要我详细展开说明的,也可以告诉我,我可以在后续进行详细介绍,不过本次仅仅介绍组件的基本概念,后续再在源码中详细介绍。

    package netty;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    public class DiscardServer {
        private int port;
    
        public DiscardServer(int port) {
            this.port = port;
        }
    
        public void run() throws Exception {
            EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
            EventLoopGroup workerGroup = new NioEventLoopGroup();// (1)
            try {
                // Netty的服务启用类
                ServerBootstrap b = new ServerBootstrap(); 
                b.group(bossGroup, workerGroup) // (1)
                        // 简单理解为Netty自己写了一个ServerSocketChannel接收连接请求
                        .channel(NioServerSocketChannel.class) 
                        // 可以理解我们给SocketChannel添加handler对其进行处理
                        .childHandler(new ChannelInitializer<SocketChannel>() { 
                            @Override
                            public void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addLast(new DiscardServerHandler()); //(2)
                            }
                        })
                        //对NioServerSocketChannel进行配置
                        .option(ChannelOption.SO_BACKLOG, 128)  
                        //对SocketChannel进行配置
                        .childOption(ChannelOption.SO_KEEPALIVE, true);
    
                // 绑定端口开始接收请求
                ChannelFuture f = b.bind(port).sync();
                // 简单理解为关闭服务
                f.channel().closeFuture().sync();
            } finally {
                workerGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();
            }
        }
    
        public static void main(String[] args) throws Exception {
            int port = 8080;
            if (args.length > 0) {
                port = Integer.parseInt(args[0]);
            }
    
            new DiscardServer(port).run();
        }
    }
    package netty;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    
    /**
     * 自定义处理I/O请求
     */
    public class DiscardServerHandler extends ChannelInboundHandlerAdapter {//(3)
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            // 丢弃接收到的数据.
            ((ByteBuf) msg).release(); 
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            // 当发生异常时关闭连接.
            cause.printStackTrace();
            ctx.close();
        }
    
    }

在接下来两章中详细讲解一下上述代码注释(1)、(2)的基本概念和理解。