【Netty】 工作原理详解(十一)
文章目录
- 前言
- 一、Netty 模型
- 二、代码示例
- 2.1、引入Maven依赖
- 2.2、服务端的管道处理器
- 2.3、服务端主程序
- 2.4、客户端管道处理器
- 2.5、客户端主程序
- 2.6、测试运行
- 总结
前言
回顾Netty系列文章:
- Netty 概述(一)
- Netty 架构设计(二)
- Netty Channel 概述(三)
- Netty ChannelHandler(四)
- ChannelPipeline源码分析(五)
- 字节缓冲区 ByteBuf (六)(上)
- 字节缓冲区 ByteBuf(七)(下)
- Netty 如何实现零拷贝(八)
- Netty 程序引导类(九)
- Reactor 模型(十)
一、Netty 模型
下图就是 Netty 的工作原理图:

执行流程如下:
-
Netty 抽象出两组线程池 BossGroup 专门负责接收客户端的连接,WorkerGroup 专门负责网络的读写。
-
BossGroup 和 WorkerGroup 类型都是 NioEventLoopGroup。
-
NioEventLoopGroup 相当于一个事件循环组,这个组中含有多个事件循环 ,每一个事件循环是 NioEventLoop。
-
NioEventLoop 表示一个不断循环的执行处理任务的线程, 每个NioEventLoop 都有一个selector ,用于监听绑定在其上的 socket 的网络通讯。
-
NioEventLoopGroup 可以有多个线程,即可以含有多个 NioEventLoop。
-
每个Boss NioEventLoop 循环执行的步骤有3步 :
- 轮询accept 事件 ;
- 处理accept 事件 ,与 client 建立连接 ,生成 NioScocketChannel,并将其注册到某个 worker NIOEventLoop 上的 selector;
- 处理任务队列的任务 , 即 runAllTasks。
-
每个 Worker NIOEventLoop 循环执行的步骤 :
- 轮询read,write 事件 处理 I/O 事件, 即 read , write 事件;
- 在对应NioScocketChannel处理;
- 处理任务队列的任务 , 即 runAllTasks;
-
每个Worker NIOEventLoop 处理业务时,会使用pipeline(管道),pipeline 中包含了channel ,即通过pipeline 可以获取到对应通道,管道中维护了很多的 处理器(ChannelHandler)。
二、代码示例
2.1、引入Maven依赖
<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.49.Final</version>
</dependency>
2.2、服务端的管道处理器
public class NettyServerHandler extends ChannelInboundHandlerAdapter {//读取数据实际(这里我们可以读取客户端发送的消息)/*1. ChannelHandlerContext ctx:上下文对象, 含有 管道pipeline , 通道channel, 地址2. Object msg: 就是客户端发送的数据 默认Object*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {System.out.println("server ctx =" + ctx);Channel channel = ctx.channel();//将 msg 转成一个 ByteBuf//ByteBuf 是 Netty 提供的,不是 NIO 的 ByteBuffer.ByteBuf buf = (ByteBuf) msg;System.out.println("客户端发送消息是:" + buf.toString(CharsetUtil.UTF_8));System.out.println("客户端地址:" + channel.remoteAddress());}//数据读取完毕@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {//writeAndFlush 是 write + flush//将数据写入到缓存,并刷新//一般讲,我们对这个发送的数据进行编码ctx.writeAndFlush(Unpooled.copiedBuffer("公司最近账户没啥钱,再等几天吧!", CharsetUtil.UTF_8));}//处理异常, 一般是需要关闭通道@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}
}
2.3、服务端主程序
public class NettyServer {public static void main(String[] args) throws Exception {//创建BossGroup 和 WorkerGroup//说明//1. 创建两个线程组 bossGroup 和 workerGroup//2. bossGroup 只是处理连接请求 , 真正的和客户端业务处理,会交给 workerGroup完成//3. 两个都是无限循环//4. bossGroup 和 workerGroup 含有的子线程(NioEventLoop)的个数// 默认实际 cpu核数 * 2//EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup(); //8try {//创建服务器端的启动对象,配置参数ServerBootstrap bootstrap = new ServerBootstrap();//使用链式编程来进行设置bootstrap.group(bossGroup, workerGroup) //设置两个线程组.channel(NioServerSocketChannel.class) //bossGroup使用NioSocketChannel 作为服务器的通道实现.option(ChannelOption.SO_BACKLOG, 128) // 设置线程队列得到连接个数 option主要是针对boss线程组,.childOption(ChannelOption.SO_KEEPALIVE, true) //设置保持活动连接状态 child主要是针对worker线程组.childHandler(new ChannelInitializer<SocketChannel>() {//workerGroup使用 SocketChannel创建一个通道初始化对象 (匿名对象)//给pipeline 设置处理器@Overrideprotected void initChannel(SocketChannel ch) throws Exception {//可以使用一个集合管理 SocketChannel, 再推送消息时,可以将业务加入到各个channel 对应的 NIOEventLoop 的 taskQueue 或者 scheduleTaskQueuech.pipeline().addLast(new NettyServerHandler());}}); // 给我们的workerGroup 的 EventLoop 对应的管道设置处理器System.out.println(".....服务器 is ready...");//绑定一个端口并且同步, 生成了一个 ChannelFuture 对象//启动服务器(并绑定端口)ChannelFuture cf = bootstrap.bind(7788).sync();//给cf 注册监听器,监控我们关心的事件cf.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture future) throws Exception {if (cf.isSuccess()) {System.out.println("服务已启动,端口号为7788...");} else {System.out.println("服务启动失败...");}}});//对关闭通道进行监听cf.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
NioEventLoopGroup是用来处理I/O操作的多线程事件循环器。Netty 提供了许多不同的EventLoopGroup的实现来处理不同的传输。
上面的服务端应用中,有两个NioEventLoopGroup被使用。第一个叫作bossGroup,用来接收进来的连接。第二个叫作workerGroup,用来处理已经被接收的连接,一旦 bossGroup接收连接,就会把连接的信息注册到workerGroup上。
ServerBootstrap是一个NIO服务的引导启动类。可以在这个服务中直接使用Channel。
- group方法用于 设置EventLoopGroup。
- 通过Channel方法,可以指定新连接进来的Channel类型为NioServerSocketChannel类。
- childHandler用于指定ChannelHandler,也就是前面实现的NettyServerHandler。
- 可以通过option设置指定的Channel来实现NioServerSocketChannel的配置参数。
- childOption主要设置SocketChannel的子Channel的选项。
- bind用于绑定端口启动服务。
2.4、客户端管道处理器
public class NettyClientHandler extends ChannelInboundHandlerAdapter {//当通道就绪就会触发该方法@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("client ctx =" + ctx);ctx.writeAndFlush(Unpooled.copiedBuffer("老板,工资什么时候发给我啊?", CharsetUtil.UTF_8));}//当通道有读取事件时,会触发@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf buf = (ByteBuf) msg;System.out.println("服务器回复的消息:" + buf.toString(CharsetUtil.UTF_8));System.out.println("服务器的地址: "+ ctx.channel().remoteAddress());}//处理异常, 一般是需要关闭通道@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}
2.5、客户端主程序
public class NettyClient {public static void main(String[] args) throws Exception {//客户端需要一个事件循环组EventLoopGroup group = new NioEventLoopGroup();try {//创建客户端启动对象//注意客户端使用的不是 ServerBootstrap 而是 BootstrapBootstrap bootstrap = new Bootstrap();//设置相关参数bootstrap.group(group) //设置线程组.channel(NioSocketChannel.class) // 设置客户端通道的实现类(反射).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new NettyClientHandler()); //加入自己的处理器}});System.out.println("客户端 ok..");//启动客户端去连接服务器端//关于 ChannelFuture 要分析,涉及到netty的异步模型ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 7788).sync();//给关闭通道进行监听channelFuture.channel().closeFuture().sync();} finally {group.shutdownGracefully();}}
}
客户端只需要一个NioEventLoopGroup就可以了。
2.6、测试运行
分别启动服务器 NettyServer 和客户端 NettyClient程序
服务端控制台输出内容:
服务器 is ready...
服务已启动,端口号为7788...
server ctx =ChannelHandlerContext(NettyServerHandler#0, [id: 0xa1b2233c, L:/127.0.0.1:7788 - R:/127.0.0.1:63239])
客户端发送消息是:老板,工资什么时候发给我啊?
客户端地址:/127.0.0.1:63239
客户端控制台输出内容:
客户端 ok..
client ctx =ChannelHandlerContext(NettyClientHandler#0, [id: 0x21d6f98e, L:/127.0.0.1:63239 - R:/127.0.0.1:7788])
服务器回复的消息:公司最近账户没啥钱,再等几天吧!
服务器的地址: /127.0.0.1:7788
至此,一个简单的基于Netty开发的服务端和客户端就完成了。
总结
本篇文章主要讲解了 Netty 的工作原理及简单应用。下节我们来讲解 Netty 的编解码。
。
相关文章:
【Netty】 工作原理详解(十一)
文章目录 前言一、Netty 模型二、代码示例2.1、引入Maven依赖2.2、服务端的管道处理器2.3、服务端主程序2.4、客户端管道处理器2.5、客户端主程序2.6、测试运行 总结 前言 回顾Netty系列文章: Netty 概述(一)Netty 架构设计(二&…...
SQL面试必备:100道高频考题解析
前言 在众多IT职场中,SQL技术一直是一个非常重要的技能点。如果你正在准备SQL相关的面试,那么这份“SQL面试 100 问”绝对是你不能错过的宝藏! 这份清单涵盖了100道高频考题,从基础知识到复杂应用都有所涉及,帮助你全…...
基于区域的图像分割
文章目录 基于区域的图像分割基本原理常用的算法实现步骤示例代码结论 基于区域的图像分割 基于区域的图像分割是数字图像处理中常用的一种方法,它通过将图像中的像素分配到不同的区域或对象来实现图像分割的目的。相比于基于边缘或阈值的方法,基于区域…...
【Python json】零基础也能轻松掌握的学习路线与参考资料
Python中的JSON模块主要用于将Python对象序列化成JSON数据或解析包含JSON数据的字符串。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。由于JSON在Web应用中的广泛使用…...
大数据开发之Hive案例篇8-解析XML
文章目录 一. 问题描述二. 解决方案2.1 官方文档2.2 XML格式不规范 一. 问题描述 今天接到一个新需求,hive表里面有个字段存储的是XML类型数据 数据格式: <a><b>bb</b><c>cc</c> </a>二. 解决方案 2.1 官方文档 遇到不懂的…...
Sentinel降级规则
1.降级规则简介 官方文档 熔断降级概述 除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的…...
基于非靶向和靶向代谢组学分析婴幼儿血管瘤的氨基酸代谢
文章标题:Integrated nontargeted and targeted metabolomics analyses amino acids metabolism in infantile hemangioma 发表期刊:Frontiers in Oncology 影响因子:5.738 作者单位:四川大学华西医院 百趣提供服务…...
程序员困局:去大城市进大厂却买不了房,回老家又没有高薪工作…
对于在外打拼的程序员来说,难的是进大厂,而不是买不起房。 进大厂的程序员,能不能买得起房? 进大厂的程序员的薪资,还是相当可观的。以阿里P6为例,年薪50万,到手40万左右,刨去10万…...
数字化转型下企业 IT 发展趋势-大企业自主研发,中小企业上云
在当今数字化转型的时代,企业IT发展面临着许多挑战和机遇。对于大中小型企业而言,数字化转型已成为实现竞争优势和业务增长的关键因素之一。在这个过程中,大企业和中小企业采取了不同的策略来推动其IT发展,其中大企业更加注重自主…...
【Go语言从入门到实战】面向对象编程篇
面向对象编程 Go语言的面向对象编程和其他语言有非常大的差别。 Go 是一种面向对象的语言吗? 是和不是。虽然 Go 有类型和方法,并允许面向对象的编程风格,但没有类型层次结构(继承)。Go 中的“接口”概念提供了一种不…...
代码随想录算法训练营第四十五天 | 力扣 70. 爬楼梯(进阶), 322. 零钱兑换, 279.完全平方数
70. 爬楼梯(进阶) 题目 70. 爬楼梯 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 改为:一步一个台阶,两个台阶,三个台阶ÿ…...
dvwa靶场通关(三)
第三关:CSRF(跨站请求伪造) csrf跨站请求伪造:是一种对网站的恶意利用。尽管听起来像跨站脚本,但它与xss非常不同,xss利用站点内受信任用户,而csrf则通过伪造来自受信任用户的请求来利用受信任…...
【计算机图形学】理论考核回顾
写在前面: 1:题型主要是单选题多选题判断题计算题,题目量居多,一定要合理安排时间。 2:小题由于太琐碎了,遂不回顾,大致都是课件上做过的小题,嗯。 3:后续有时间更新期…...
一文了解国内外电子后视镜(CMS)现行法规标准
摘要: 本文小编分享一篇整合了国内外对CMS的安装及功能性做出要求的相关标准与法规。感兴趣的朋友可以专门去搜索学习。 前言:随着GB15084-2022的即将正式实施,以摄像头屏幕组合取代传统光学后视镜的新一代电子后视镜CMS相关车型将被允许上路…...
LabVIEWCompactRIO 开发指南36 确定“Clock Ticks”或模拟时间
LabVIEWCompactRIO 开发指南36 确定“Clock Ticks”或模拟时间 桌面执行节点可以控制模拟时间,因此开发人员可以使用模拟I/O在开发计算机上执行期间更改关键点的激励。要成功使用此功能,需要测量FPGA VI完成所需的时间,或者需要以直观地知道…...
ESP32 :项目的创建及项目架构解析
一、项目的创建 方式一:基于IDF示例创建 在ESP-IDF中有example示例库,以其中的一个示例为模板创建项目。 1、打开示例库 查看 - 命令面板(也可以按住CtrlShiftP 或 F1) 输入 show examples projects 2…...
TI EDI 项目数据库方案开源介绍
TI EDI 工作流简介 TI EDI到SQL Server示例流具有预配置的端口,用于从TI的EDI集成规范转换以下交易集: 850 采购订单,企业 -> TI855 采购订单确认,TI -> 企业860 采购订单变更,企业 -> TI865 采购订单变更确认,TI -> 企业856 发货通知,TI …...
报表控件FastReport使用指南——使用NuGet包创建PDF文档
FastReport 是功能齐全的报表控件,可以帮助开发者可以快速并高效地为.NET,VCL,COM,ActiveX应用程序添加报表支持,由于其独特的编程原则,现在已经成为了Delphi平台最优秀的报表控件,支持将编程开…...
策略模式-类型统计
文章目录 前言一、策略模式是什么?二、策略模式应用场景三、策略模式优点四、策略模式缺点五、场景案例:类型统计1.项目结构2.UML图解3.代码实现3.1 指标枚举3.2 请求体3.3 响应体3.4.分析统计指标策略3.5.接口3.6.扩展接口3.7.接口实现3.8.控制层 六、P…...
android 12.0app应用安装白名单
1.概述 在12.0定制化开发中,客户需求要实现应用安装白名单功能,在白名单之中的应用可以安装,其他的app不准安装,实现一个 控制app安装的功能,这需要从app安装流程入手就可以实现功能 PMS就是负责管理app安装的,功能就添加在这里就可以了, 2.app应用安装白名单核心代码 …...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
软件工程 期末复习
瀑布模型:计划 螺旋模型:风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合:模块内部功能紧密 模块之间依赖程度小 高内聚:指的是一个模块内部的功能应该紧密相关。换句话说,一个模块应当只实现单一的功能…...
多元隐函数 偏导公式
我们来推导隐函数 z z ( x , y ) z z(x, y) zz(x,y) 的偏导公式,给定一个隐函数关系: F ( x , y , z ( x , y ) ) 0 F(x, y, z(x, y)) 0 F(x,y,z(x,y))0 🧠 目标: 求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z、 …...
【汇编逆向系列】六、函数调用包含多个参数之多个整型-参数压栈顺序,rcx,rdx,r8,r9寄存器
从本章节开始,进入到函数有多个参数的情况,前面几个章节中介绍了整型和浮点型使用了不同的寄存器在进行函数传参,ECX是整型的第一个参数的寄存器,那么多个参数的情况下函数如何传参,下面展开介绍参数为整型时候的几种情…...
