• Netty 01 从EchoServer 开始抛砖引玉


    Netty 01 从EchoServer 开始抛砖引玉

    Netty 服务端开发可能涉及下面这些类,对第一次接触Netty的同学一下接触这么多类,千万别它震慑,其实Netty Server端或者Client代码总体比较固定,我们几乎只需要编写自己的编码器、解码器

    • EventLoop
    • EventLoopGroup
    • ChannelPipeline
    • Channel
    • ChannelInitializer
    • ChannelHandler

    先感受Netty 开发服务端程序步骤

    • 配置 EventLoopGroup

      可以理解为线程池,一个接受客户端连接,一个处理IO读写请求

    • 配置Channel为NioServerSocketChannel

      如果基于传统阻塞IO,可以使用OioServerSocketChannel

    • 配置消息处理器责任链

      这里需要定义业务自己的处理逻辑,当然也可以使用内置的处理器,一般需要和内置的处理器集合起来使用

    • 绑定端口

    • 释放资源

    基于Netty 实现

    实现需要引入依赖

            <dependency>
                <groupId>io.nettygroupId>
                <artifactId>netty-allartifactId>
                <version>4.1.68.Finalversion>
            dependency>
    
    

    Netty 实现EchoServer ,实际上我们只实现了 NettyEchoServerHandler,将接收到的消息原封不动的发出去。

    Netty内置了许多编码器、解码器如StringDecoder、StringEncoder,当然还有许多其他编码器,解码器。

    ch.pipeline().addLast 可以初步推断这是一个责任链模式,这就意味着,许多处理器可以结合起来使用,使得开发者很容易在内置处理器基础上,扩展新功能。

    
    public class NettyEchoServer {
        private int port;
    
        public NettyEchoServer(int port) {
            this.port = port;
        }
    
        public void run() throws Exception {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                ServerBootstrap b = new ServerBootstrap();
                b.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            public void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addLast("decoder", new StringDecoder());
                                ch.pipeline().addLast("encoder", new StringEncoder());
                                ch.pipeline().addLast(new NettyEchoServerHandler());
                            }
                        });
    
                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; // 设置服务端监听端口
            new NettyEchoServer(port).run();
        }
    }
    
    
    public class NettyEchoServerHandler extends SimpleChannelInboundHandler<String> {
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
            System.out.println("Server received: " + msg);
            ctx.writeAndFlush( msg);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }
    
    

    NIO 实现 EchoServer

    回顾下 NIO 大概流程

    • 创建 Selector
    • 打开 Channel 并设置为非阻塞模式
    • 将 Channel 注册到 Selector 上,并指定感兴趣的事件类型
    • 在循环中调用 select() 方法,等待事件发生
    • 处理相应事件

    NIO如何实现EchoServer关键代码,相比Netty 直观感受Netty几个优势。当然随着深入学习,你将会感受到Netty的强大,本文只是入门。

    • NIO需要自己将Buffer 解析成我们的消息结构,Netty内置了许多处理器,消息处理更简单

    • NIO 扩展性不好,当然我们该程序没有好好设计,而netty 我们就很容易在 pipeline 添加我们的处理器,扩展很容易。

    • 性能方面

      Netty使用不同的EventLoopGroup 接受连接和处理IO读写,开发者只需要调整相关参数即可, NIO 可能依赖开发者​处理。

    public static void main(String[] args) throws IOException {
            // 打开选择器
            Selector selector = Selector.open();
    
            // 打开服务器套接字通道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false); // 设置为非阻塞模式
            serverSocketChannel.socket().bind(new InetSocketAddress(PORT));
    
            // 将服务器套接字通道注册到选择器上,并且只关心接受事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    
            System.out.println("NIO Echo Server started on port " + PORT);
    
            while (true) {
                // 阻塞直到有至少一个注册的选择键就绪
                selector.select();
    
                // 获取就绪的选择键集合
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectedKeys.iterator();
    
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
    
                    if (key.isAcceptable()) { // 新的连接请求
                        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                        SocketChannel client = ssc.accept();
                        if (client == null){
                            return; // 可能没有可用的客户端
                        }
                        client.configureBlocking(false);
    
                        // 将新连接注册到 Selector 上,监听读取事件,并附带 ReadHandler
                        client.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE, ByteBuffer.allocate(BUFFER_SIZE));
                    }
    
                    if (key.isReadable()) { // 可读数据
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer output = (ByteBuffer) key.attachment();
                        client.read(output);
                    }
    
                    if(key.isWritable()){
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer output = (ByteBuffer) key.attachment();
                        output.flip();
                        client.write(output);
                        output.compact();
                    }
    
                    iterator.remove(); // 处理完后移除选择键
                }
            }
        }
    
    
    
  • 相关阅读:
    uni-app:服务器端数据绘制多个echarts图标(renderjs解决手机端无法显示问题)
    Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法
    Odoo 15开发手册第八章 业务逻辑 - 业务流程的支持
    YOLOV7详细解读(一)网络架构解读
    Mybatis-尚硅谷-学习笔记
    ClickHouse开发系列
    牛客网刷题——java
    Java开发 - Canal进阶之和Redis的数据同步
    用于微小目标检测的上下文扩展和特征细化网络
    MySQL索引
  • 原文地址:https://blog.csdn.net/happycao123/article/details/143440013