Netty入门——组件(Channel)二

news2025/9/15 1:28:43

目录

    • 一、channel的主要作用
    • 二、EventLoop处理io任务代码示例
      • 2.1、服务端代码示例
      • 2.2、客户端代码示例
      • 2.3、服务端和客户端查看控制台输出结果
    • 三、CloseFuture关闭问题代码示例
      • 3.1、服务端代码示例
      • 3.2、客户端代码示例
      • 3.3、服务端和客户端查看控制台输出结果
      • 3.4、CloseFuture关闭问题出现的原因
    • 四、CloseFuture关闭问题的处理方式一(获取 CloseFuture 对象,同步处理关闭)
      • 4.1、服务端代码示例
      • 4.2、客户端代码示例
      • 4.3、服务端和客户端查看控制台输出结果
    • 五、CloseFuture关闭问题的处理方式二(获取 CloseFuture 对象,异步处理关闭)
      • 5.1、服务端代码示例
      • 5.2、客户端代码示例
      • 5.3、服务端和客户端查看控制台输出结果

一、channel的主要作用

channel 中的方法作用
close()用来关闭 channel
closeFuture()处理 channel 的关闭,sync 方法作用是同步等待 channel 关闭,addListener 方法是异步等待 channel 关闭
pipeline()添加处理器
write()将数据写入
writeAndFlush()将数据写入并刷出

二、EventLoop处理io任务代码示例

2.1、服务端代码示例

  • 引入pom依赖

     <dependency>
         <groupId>io.netty</groupId>
         <artifactId>netty-all</artifactId>
         <version>4.1.39.Final</version>
     </dependency>
    
  • 服务端

    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.DefaultEventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import lombok.extern.slf4j.Slf4j;
    
    import java.nio.charset.Charset;
    
    /**
     * @description: EventLoop处理io任务 服务端
     * @author: xz
     */
    @Slf4j
    public class EventLoopServer {
        public static void main(String[] args) {
            //创建一个独立的EventLoopGroup
            DefaultEventLoopGroup normalWorkers = new DefaultEventLoopGroup(2);
            //1、服务端启动器:负责组装netty组件
            new ServerBootstrap()
                    //2、将EventLoop分为boss和worker(即将EventLoop分工细化)
                    // boss即第1个参数,只负责accept事件; worker即第2个参数,只负责socketChannel上的读写
                    .group(new NioEventLoopGroup(1), new NioEventLoopGroup(2))
                    //3、选择服务器的 ServerSocketChannel 实现
                    .channel(NioServerSocketChannel.class)
                    //4、添加服务端处理器
                    .childHandler(
                        // 5. channel 代表和客户端进行数据读写的通道 Initializer 初始化,负责添加别的 handler
                        new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            //6、添加具体 handler
                            ch.pipeline().addLast(normalWorkers,"handler1", new ChannelInboundHandlerAdapter() {
                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                    //msg转ByteBuf
                                    ByteBuf buf = (ByteBuf) msg;
                                    //ByteBuf转字符串
                                    log.debug(buf.toString(Charset.defaultCharset()));
                                    //让消息传递给下一个handler
                                    ctx.fireChannelRead(msg);
                                }
                            });
                        }
                    })
                    //7、绑定监听端口
                    .bind(8080);
        }
    }
    

2.2、客户端代码示例

  • 客户端

    import io.netty.bootstrap.Bootstrap;
    import io.netty.buffer.ByteBufAllocator;
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import io.netty.handler.codec.string.StringEncoder;
    import lombok.extern.slf4j.Slf4j;
    import java.net.InetSocketAddress;
    /**
     * @description: EventLoop处理io任务 客户端
     * @author: xz
     */
    @Slf4j
    public class EventLoopClient {
        public static void main(String[] args) throws InterruptedException {
            // 1. 客户端启动器
            Channel channel = new Bootstrap()
                    // 2. 添加 EventLoop(事件循环)
                    .group(new NioEventLoopGroup(1))
                    // 3. 选择客户端的 SocketChannel 实现
                    .channel(NioSocketChannel.class)
                    // 4. 添加客户端处理器
                    .handler(new ChannelInitializer<NioSocketChannel>() {
                        // 在连接建立后被调用
                        @Override
                        protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                            //9. 消息会经过通道 handler 处理,这里是将 String => ByteBuf 发出
                            nioSocketChannel.pipeline().addLast(new StringEncoder());
                        }
                    })
                    //5. 连接到服务器
                    .connect(new InetSocketAddress("localhost", 8080))
                    //6. 等待 connect 建立连接完毕
                    .sync()
                    //7. 连接对象
                    .channel();
            System.out.println("打印channel对象==="+channel);
            //8. 发送数据
            channel.writeAndFlush(ByteBufAllocator.DEFAULT.buffer().writeBytes("aaaaaa".getBytes()));
        }
    }
    

2.3、服务端和客户端查看控制台输出结果

  • 先启动服务端,再启动客户端,查看客户端控制台输出,结果如下:
    在这里插入图片描述
  • 再查看服务端控制台输出,结果如下:
    在这里插入图片描述

三、CloseFuture关闭问题代码示例

3.1、服务端代码示例

  • 同步2.1步骤中的代码

3.2、客户端代码示例

  • 将2.2步骤中客户端代码拆开,代码如下

    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelFutureListener;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import io.netty.handler.codec.string.StringEncoder;
    import io.netty.handler.logging.LogLevel;
    import io.netty.handler.logging.LoggingHandler;
    import lombok.extern.slf4j.Slf4j;
    import java.net.InetSocketAddress;
    import java.util.Scanner;
    
    /**
     * @description: EventLoop处理io任务中CloseFuture连接问题及处理结果
     * @author: xz
     */
    @Slf4j
    public class CloseFutureClient {
        public static void main(String[] args) throws InterruptedException {
            client1();
        }
        /**
         * 将客户端代码拆开
         * ChannelFuture关闭问题 : 不能保证 log输出的处理关闭之后的操作 一定是在真正的channel.close()之后执行
         * */
        public static void client1() throws InterruptedException {
            ChannelFuture channelFuture = new Bootstrap()
                    .group(new NioEventLoopGroup(1))
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                            nioSocketChannel.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                            nioSocketChannel.pipeline().addLast(new StringEncoder());
                        }
                    })
                    //1、连接到服务器
                    //异步非阻塞,main方法发起了调用,真正执行connect是nio线程
                    .connect(new InetSocketAddress("localhost", 8080));
            //无阻塞向下执行获取channel
            Channel channel = channelFuture.sync().channel();
            log.info("建立连接后,打印channel对象====={}",channel);
    
            /**
             * 启动一个新的线程
             * */
            new Thread(()->{
                Scanner scanner = new Scanner(System.in);
                while(true){
                    String line = scanner.nextLine();
                    if("q".equals(line)){
                        channel.close();// close 异步操作
                        break;
                    }
                    channel.writeAndFlush(line);
                }
            },"input").start();
    		log.debug("处理关闭之后的操作");
        }
    }
    

3.3、服务端和客户端查看控制台输出结果

  • 先启动服务端,再启动客户端,查看客户端控制台输出,结果如下:

    在这里插入图片描述

  • 再查看客户端控制台输出,结果如下:

    在这里插入图片描述

3.4、CloseFuture关闭问题出现的原因

  • 由上述代码示例可知,ChannelFuture关闭问题 : 不能保证 log输出的处理关闭之后的操作 一定是在真正的channel.close()之后执行。

四、CloseFuture关闭问题的处理方式一(获取 CloseFuture 对象,同步处理关闭)

4.1、服务端代码示例

  • 同步2.1步骤中的代码

4.2、客户端代码示例

  • 将3.2步骤中客户端代码进行修改,代码如下

    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelFutureListener;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import io.netty.handler.codec.string.StringEncoder;
    import io.netty.handler.logging.LogLevel;
    import io.netty.handler.logging.LoggingHandler;
    import lombok.extern.slf4j.Slf4j;
    import java.net.InetSocketAddress;
    import java.util.Scanner;
    
    /**
     * @description: EventLoop处理io任务中CloseFuture连接问题及处理结果
     * @author: xz
     */
    @Slf4j
    public class CloseFutureClient {
        public static void main(String[] args) throws InterruptedException {
            client2();
        }
        /**
         * 将客户端代码拆开
         * ChannelFuture关闭问题的处理方式一 :获取 CloseFuture 对象,同步处理关闭
         * */
        public static void client2() throws InterruptedException {
            ChannelFuture channelFuture = new Bootstrap()
                    .group(new NioEventLoopGroup(1))
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                            nioSocketChannel.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                            nioSocketChannel.pipeline().addLast(new StringEncoder());
                        }
                    })
                    //1、连接到服务器
                    //异步非阻塞,main方法发起了调用,真正执行connect是nio线程
                    .connect(new InetSocketAddress("localhost", 8080));
            //无阻塞向下执行获取channel
            Channel channel = channelFuture.sync().channel();
            log.info("建立连接后,打印channel对象====={}",channel);
    
            /**
             * 启动一个新的线程
             * */
            new Thread(()->{
                Scanner scanner = new Scanner(System.in);
                while(true){
                    String line = scanner.nextLine();
                    if("q".equals(line)){
                        channel.close();// close 异步操作
                        break;
                    }
                    channel.writeAndFlush(line);
                }
            },"input").start();
            // 获取 CloseFuture 对象, 1) 同步处理关闭
            ChannelFuture closeFuture = channel.closeFuture();
            log.debug("waiting close...");
            closeFuture.sync();
            log.debug("处理关闭之后的操作");
        }
    }
    

4.3、服务端和客户端查看控制台输出结果

  • 先启动服务端,再启动客户端,查看客户端控制台输出,结果如下:
    在这里插入图片描述

  • 再查看服务端控制台输出,结果如下:

    在这里插入图片描述

五、CloseFuture关闭问题的处理方式二(获取 CloseFuture 对象,异步处理关闭)

5.1、服务端代码示例

  • 同步2.1步骤中的代码

5.2、客户端代码示例

  • 将3.2步骤中客户端代码进行修改,代码如下

    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelFutureListener;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import io.netty.handler.codec.string.StringEncoder;
    import io.netty.handler.logging.LogLevel;
    import io.netty.handler.logging.LoggingHandler;
    import lombok.extern.slf4j.Slf4j;
    import java.net.InetSocketAddress;
    import java.util.Scanner;
    
    /**
     * @description: EventLoop处理io任务中CloseFuture连接问题及处理结果
     * @author: xz
     */
    @Slf4j
    public class CloseFutureClient {
        public static void main(String[] args) throws InterruptedException {
            client3();
        }
        /**
         * 将客户端代码拆开
         * ChannelFuture关闭问题的处理方式二 :获取 CloseFuture 对象,异步处理关闭
         * */
        public static void client3() throws InterruptedException {
            ChannelFuture channelFuture = new Bootstrap()
                    .group(new NioEventLoopGroup(1))
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                            nioSocketChannel.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                            nioSocketChannel.pipeline().addLast(new StringEncoder());
                        }
                    })
                    //1、连接到服务器
                    //异步非阻塞,main方法发起了调用,真正执行connect是nio线程
                    .connect(new InetSocketAddress("localhost", 8080));
            //无阻塞向下执行获取channel
            Channel channel = channelFuture.sync().channel();
            log.info("建立连接后,打印channel对象====={}",channel);
    
            /**
             * 启动一个新的线程
             * */
            new Thread(()->{
                Scanner scanner = new Scanner(System.in);
                while(true){
                    String line = scanner.nextLine();
                    if("q".equals(line)){
                        channel.close();// close 异步操作
                        break;
                    }
                    channel.writeAndFlush(line);
                }
            },"input").start();
            // 获取 CloseFuture 对象, 2) 异步处理关闭
            ChannelFuture closeFuture = channel.closeFuture();
            log.debug("waiting close...");
            closeFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    log.debug("处理关闭之后的操作");
                }
            });
        }
    }
    

5.3、服务端和客户端查看控制台输出结果

  • 先启动服务端,再启动客户端,查看客户端控制台输出,结果如下:
    在这里插入图片描述

  • 再查看服务端控制台输出,结果如下:

    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/3129.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++ STL】-- deque与vector相比的优势与劣势

目录 deque容器 与stack相比deque的优缺点&#xff1a; deque的迭代器 deque的成员函数 deque容器 deque的相关文档 deque与vector十分的相识。vector是单向开口的连续线性空间&#xff08;单向扩容&#xff09;&#xff0c;deque则是一种双向开口的连续线性空间&#xff…

GIC/ITS代码分析(9)中断应用实例之IPI中断

PPI中断为外设私有中断&#xff0c;在ARM64上arch_timer为PPI中断。这里以arch_timer为例&#xff08;代码位置drivers/clocksource/arm_arch_timer.c&#xff09;&#xff0c;作应用实例讲解。 先对ARM64通用定时器作简要介绍。通用定时器为Arm core提供标准定时器。通用定时器…

VSCode下载安装与使用教程

目录1. 打开官网进行下载安装2. 下载3. 安装4. 使用4.1 python extensions4.2 建立 python 工作区4.3 运行python代码的 3 种方法方法一&#xff1a;点击按钮方法二&#xff1a;右键菜单方法三&#xff1a;交互式解释器5. debug参考资料VSCode是一款免费开源的现代化轻量级代码…

【C++修炼之路】8. string类详解

每一个不曾起舞的日子都是对生命的辜负 C之string类本节目标1. string类概览1.1 string的由来1.2 string函数列表2.string常用接口1. 初始化2. string::npos3. c_str()4. 获取长度&#xff08;length、size)5. 容量&#xff08;size、capacity)6. 插入&#xff08;insert)7. 替…

牛客网-《刷C语言百题》第三期

✅作者简介&#xff1a;嵌入式入坑者&#xff0c;与大家一起加油&#xff0c;希望文章能够帮助各位&#xff01;&#xff01;&#xff01;&#xff01; &#x1f4c3;个人主页&#xff1a;rivencode的个人主页 &#x1f525;系列专栏&#xff1a;《C语言入门必刷百题》 &#x…

【HTML5期末大作业】制作一个简单HTML我的班级网页(HTML+CSS+JS)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

微信小程序 |从零实现酷炫纸质翻页效果

&#x1f4cc;个人主页&#xff1a;个人主页 ​&#x1f9c0; 推荐专栏&#xff1a;小程序开发成神之路 --【这是一个为想要入门和进阶小程序开发专门开启的精品专栏&#xff01;从个人到商业的全套开发教程&#xff0c;实打实的干货分享&#xff0c;确定不来看看&#xff1f; …

保姆级透明背景动画导出 —— json格式(Mac系统)

日常能想到的小动画基本就是使用ps导出GIF动画/AE通过插件直接导出GIF&#xff0c;方便快捷&#xff1b;但最近工作中遇到了关于透明背景导出GIF动画的问题&#xff1a;导出的GIF动画有白边&#xff0c;有锯齿感。 网上找了一大堆教程&#xff0c;主要原因出在GIF格式本身的问…

黑马程序员Java实战项目--- ATM系统

项目介绍与功能演示 黑马银行ATM系统技术选型分析&#xff1a; 学习本项目&#xff0c;你将至少得到如下收获&#xff1a; 1、优秀的面向对象编程能力。 2、 清晰、缜密的业务、数据分析能力。 3、熟练使用程序流程技术来控制计算机完成自己的想法。 4、形成良好的编码习惯…

【面试题】移除数组删除重复项合并数组

1️⃣ 原地移除数组中所有的元素val 【OJ链接】 2️⃣ 删除排序数组中的重复项 【OJ链接】 3️⃣ 合并两个有序数组 【OJ链接】 1️⃣ 原地移除数组中所有的元素val 题目要求是要在数组中&#xff0c;把指定的数字全部去除&#xff0c;题目中也是强调了空间复杂度要求为O(1)&am…

项目经理要“谋定而后动,知止而有得,万事皆有法,不可乱也”

出自《大学》&#xff0c;“谋定而后动&#xff0c;知止而有得”的含义为谋划准确周到而后行动&#xff0c;知道目的地&#xff08;合适的时机收手&#xff09;才能够有所收获。 谋定而后动是告诉我们做任何事一定要进行谋划部署&#xff0c;做好准备&#xff0c;我们才能开始行…

数据结构作业:时间复杂度和二叉树

计算时间复杂度&#xff1a; int x0,i,j; 1 for(i1;i<n;i) n { for(j1;j<2*i;j) 2(n-1) { x; 2(n-1)*n } } 2(n-1)*n2n^2-2n 修改后的运行次数函数中&#xff0c;只保留最高阶项。 所以时间复杂度为 &#xff1a;…

老生常谈的商城系统(Asp.Net+uniapp)

真正的大师,永远都怀着一颗学徒的心&#xff01; 最近几天合肥是真热 这时候就应该宅在家里 吃着西瓜 啃着鸭脖 喝着啤酒 刷着剧 想想也太美好了吧 哈哈 我得醒醒 写完这篇推荐 吃吃喝喝去了 一、项目简介 今天推荐一款商城系统&#xff0c;虽然比较老生常谈了&#xff0…

【项目】若依框架如何实现批量导入,并解析出表中内容返回给前端? - poi依赖

文章目录实现效果&#xff1a;具体实现步骤&#xff1a;扩展实例内容&#xff1a;poi工具包ExcelHandlerAdapter接口ExcelUtil.java代码controllerserviceserviceImplmapper.javamapper.xmlTnProductProperty.java实现效果&#xff1a; 点击“导入excl”按钮 --> 弹出“文件…

MSDC 4.3 接口规范(27)

MSDC 4.3 接口规范&#xff08;27&#xff09;7.4.4 代码7.4.5 更新组呼业务7.4.5.1 接口函数7.4.5.2 先决条件7.4.5.3 说明7.4.5.4 调用流程7.4.6 其他信息通知7.4.6.1 组呼服务停止7.4.6.1.1 接口函数7.4.6.1.2 先决条件7.4.6.1.3 说明7.4.6.1.4 调用流程7.4.6.2 SAI 列表更新…

Nginx禁止文件下载防止服务器被恶意扫描

比如将网站数据库导出到站点根目录进行备份&#xff0c;很有可能也会被别人下载&#xff0c;从而导致数据丢失的风险。以下规则可以防止一些常规的文件被下载&#xff0c;可根据实际情况增减。我们可以通过以下俩种方法来防止服务器被恶意扫描&#xff0c;其中以彼之道&#xf…

ffmpeg解复用FLV文件

该博文是基于&#xff1a; ffmpeg&#xff1a;V 5.1.2 FLV格式是H2.64视频和aac音频复用得到的格式&#xff0c;我们所说的FLV解复用就是将FLV格式的数据的H2.64视频帧和aac音频帧分离。 分离完成后&#xff0c;音频是纯数据无法播放&#xff0c;需要添加ADTS头&#xff0c;视频…

浅谈基于以太网的煤矿电力监控系统的设计与应用

王兰 安科瑞电气股份有限公司 上海嘉定 201801 摘 要&#xff1a;针对传统煤矿电力监控系统通讯网络性能较差、无法实现准确故障定位及报警、不具备数据交互功能等问题&#xff0c;结合分布式网络及GPS授时技术设计了一套基于工业以太网及RS485总线架构的煤矿电力监控系…

第二十三课.扩散模型

目录概述前向过程逆向过程DDPM概述 近几年扩散模型不断涌现&#xff0c;但都来源于一个基础模型&#xff1a;DDPM&#xff08;Denoising Diffusion Probabilistic Model&#xff09;。扩散模型本质是生成模型&#xff0c;过去我们常用的生成模型包括GAN和VAE&#xff0c;利用随…

【Linux】冯诺依曼体系结构

目录&#x1f308;前言&#x1f337;1、冯诺依曼体系结构&#x1f338;2、操作系统(Operator System)&#x1f339;2.1、概念&#x1f340;2.2、如何理解管理&#x1f341;3、进程&#x1f342;3.1、概念&#x1f308;前言 本篇文章进行操作系统中进程的学习&#xff01;&…