Netty究竟是怎么运行的-连接流程的深入剖析

Netty 源码 — 线程模型的分析 文章目录Netty 线程模型分析Reactor 线程模型Netty 初始化线程池BossGroup 工作原理绑定 Channel事件循环执行 IO 事件WorkerGroup 工作总结 Netty 线程模型分析 阅读本文之前,需要了解 NIO 相关知识,可参阅我的文章:[NIO 与 epoll 知识详解](./NIO 与 epoll.md) Reactor 线程模型 Netty 的线程模型 是基于 Reactor 线程模型的,Reactor 线程模型分为三种模型: 单线程模型:注册所有感兴趣的事件,一 阅读详情

Netty究竟是怎么运行的-连接流程的深入剖析

java nio非常难驾驭,就像我在上一篇文章中处理的文件服务器那样,也只是考虑并处理了部分情况,然而可能还是要出错,可扩展性也不好。

netty就是这样的一种框架,让Java nio变得:

  • 网络服务器编程变得容易
  • 可用性变高
  • 扩展性好

netty的基本工作方式

那么,Netty究竟是怎么运行的? Netty使用多Reactor多线程模型。

这种模型是把Reactor线程拆分了mainReactor和subReactor两个部分,mainReactor只处理连接事件,读写事件交给subReactor来处理。mainRactor只处理连接事件,一个端口用一个线程来处理。处理读写事件的subReactor个数一般和操作系统核数相关,一个连接对应一个线程.业务逻辑由业务线程池处理。

本文会引用一个例子,先谈谈netty使用的基本数据结构,然后梳理清楚使用netty建立连接的过程。

从一个例子开始

maven包依赖

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.72.Final</version>
</dependency>
复制代码

server

server可以认为和我在nio的实现里面的区别是:acceptor单独一个线程池,其他io事件或者任务一个线程池。然而我当时没有这么实现,只是给业务流程一个线程池。 

netty48.png

 netty server 的代码示意如下:

public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup parentGroup = new NioEventLoopGroup();
        //NettyRuntime.availableProcessors() * 2 线程数
        EventLoopGroup childGroup = new NioEventLoopGroup();
        try {

            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(parentGroup, childGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new StringDecoder());//解码为字符串
                            pipeline.addLast(new StringEncoder());//编码为二进制
                            pipeline.addLast(new DemoSocketServerHandler());
                        }
                    });
            ChannelFuture future = bootstrap.bind(8888).sync();
            System.out.println("future.channel() = " + future.channel());
            System.out.println("服务器已启动。。。");
            future.channel().closeFuture().sync();
        } finally {
            parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();
        }
    }
}
复制代码

server bind之后会启动一个线程阻塞在select,等待着连接了。

client

netty client的编码模型简单很多,如下:

netty2.png

netty client 的代码示意如下:

Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
        .channel(NioSocketChannel.class)
        .handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
                pipeline.addLast(new DemoSocketClientHandler());
                pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));

            }
        });

ChannelFuture future = bootstrap.connect("localhost", 8888).sync();
复制代码

客户端也是一个连接池,每个连接一个线程,这里只使用一个有点浪费了,但是这里只是一个简单的demo,暂且这样处理吧。

demo总结

可以看到,总体编码简单易懂,但要明白具体的运行机制,却要费一番功夫。下面先介绍demo中用到的基本数据结构,然后再试图弄清楚netty用于连接的机理。

数据结构

如果已经比较了解这块的数据结构,可直接跳到流程部分。

Bootstrap

  • ServerBootstrap是为netty服务器设置服务的,像上面这样通过ServerBootstrap就可以配置出一个完善的netty服务来
  • Bootstrap是为netty客户端设置服务的,像上面这样通过Bootstrap就可以配置出一个完善的netty客户端

Channel

可以认为channel是一个连接,Channel聚合了一组功能,不但包括网络IO操作,还包括获取该Channel的eventloop、以及获取缓冲分配器allocator, 和pipeline等。所以channel是netty里面最重要的数据结构。

NioEventLoop

NioEventLoopGroup,主要管理 eventLoop 的生命周期,可以理解为是一个线程池。

NioEventLoop 中维护了一个线程和任务队列,支持异步提交执行任务,线程启动时会调用 NioEventLoop 的 run 方法,执行I/O任务和非 I/O 任务:

  • I/O 任务,即 selectionKey 中 ready 的事件,如 accept、connect、read、write 等,由 processSelectedKeys 方法触发。
  • 非IO 任务,添加到 taskQueue 中的任务,如 register0、bind0 等任务以及一些定时任务,由 runAllTasks 方法触发。

两种任务的执行时间比由变量 ioRatio 控制,默认为 50,则表示允许非 IO 任务执行的时间与 IO 任务的执行时间相等。

异步的api

nio编程的时候讨论到的是非阻塞的api,非阻塞是不够方便的,往往要和循环放在一起操作,比如之前的文件服务器。

netty的设计却不同,主要需要使用到异步的api,这里谈到的异步的api其实是一种软件设计上的事情,引入这个,对于Java nio编码带来了极大的帮助。

下面先了解一下什么是异步的api

Future

Future可能大家已经非常熟知了,Future是JDK中的接口,当引入线程池的时候,Future也引入了,可以用来表示提交的任务的结果。 Future接口提供两个方法:

  • get: 同步阻塞当前调用的线程,直到结果被设置
  • cancel:取消异步操作,但是结果是未知的。如果操作已经完成,或者发送其他未知的原因拒绝取消,取消操作将会失败。

ChannelFuture和Promise接口

因为netty的操作和函数都和channel相关,故而netty里面给自己的Future接口命名为ChannelFutur

2022年了,Netty究竟是怎么运行的-连接流程的深入剖析 java nio非常难驾驭,就像我在上一篇文章中处理的文件服务器那样,也只是考虑并处理了部分情况,然而可能还是要出错,可扩展性也不好。 netty就是这样的一种框架,让Java nio变得: 网络服务器编程变得容易 可用性变高 扩展性好 netty的基本工作方式 那么,Netty究竟是怎么运行的? Netty使用多Reactor多线程模型。 这种模型是把Reactor线程拆分了mainReactor和subReactor两个部分,mainReactor只处理连接事件,读写事件交给subRea.. 阅读详情

相关推荐

Netty源码分析之Reactor线程模型详解

在分析源码之前,我们先分析,哪些地方用到了EventLoop? NioServerSocketChannel的连接监听注册 NioSocketChannel的IO事件注册 NioServerSocketChannel连接监听 在AbstractBootstrap类的initAndRegister()方法中,当NioServerSocketChannel初始化完成后,会调用case标记位置的代码进行注册。 final ChannelFuture initAndRegister() { C..

m0_64821673的博客 750

Netty启动流程、NioEventLoop、读写事件源码剖析

Netty底层是NIO,从对NIO的组件封装开始看。我们来看看 netty 中对下面的代码 是怎样进行处理的。

Charte的博客 1231

Netty工作笔记0044---Netty案例源码分析

技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152 来看看前面写的案例 可以看到这个bossgroup还有workergroup的底层代码 MultithreadEventLoopGroup 这里可以看到 NettyRuntime.availableProcessors( ) * 2 这个就是获取CPU的内核数,然后*2,比如有2个cpu,一个cpu有2个核心 那么也就是这里首先workergroup会启动 2*2*2=8个线程.

添柴程序猿的专栏 530

netty服务端启动流程

说明:本文参考的 Netty 源码版本为 4.1.42.Final。 启动服务的过程中我们可以了解到 Netty 各大核心组件的关系,这将是学习 Netty 源码一个非常好的切入点,让我们一起看看 Netty 的每个零件是如何运转起来的吧。 文章目录从 Echo 服务器示例入手服务端启动全过程服务端 Channel 初始化及注册创建服务端 Channel初始化服务端 Channel注册服务端 Channel端口绑定netty服务端如何处理客户端新建连接总结 从 Echo 服务器示例入手 在这里我们实现了.

762

关于MII、RMII、GMII、RGMII、PHY、网络变压器、RJ45的硬件总结

文章目录前言一、网络传输结构及原理1.以太网的工作原理2.TCP/IP协议3.数据链路层(MAC)二、介质独立接口MII,RMII,GMII,RGMII1.MII(Media Independent interface)2.RMII(Reduced Media Independent Interface)3.GMII(Gigabit Medium Independent)4.RGMII(Reduced Gigabit Media Independent Interface)三、物理层芯片(PHY)二、使用步

weixin_44415816的博客 3万+

探测器反向偏压_光探测器PN结原理

1 光探测原理在光的作用下,当光敏物质中的电子直接吸收光子的能量足以客服原子核的束缚时,电子就会从基态被激发到高能态,脱离原子核的束缚,在外电场作用下参与导电,因而产生了光电效应。(这里需要说明的是,如果光子不是直接与电子起作用而是能量被固体晶格振动吸收,引起固体的温度升高,导致固体电学性质的改变,这种情况就不是光电效应而是热电效应)。根据所用结的种类的不同,可分为PN结,PIN 结型,...

weixin_42489104的博客 2548

Ubuntu24.04/20.04设置网络共享文件夹

Ubuntu20.04利用向日葵远程控制时,不能传输文件。使用linux版本QQ来传输是可以的,不过linuxqq功能真的很弱。因此,打算在Ubuntu系统中建立一个共享文件夹,可在局域网中访问。 1、新建共享文件夹 获取root权限,或者登陆root账户。可在/home文件夹(或其它文件夹)下新建一个文件夹,如share。 右击文件夹,选择“本地网络共享”菜单。按下图设置。 点击确定。如果系统已经安装了samba服务器,就可以进入第3步。如果没有,会提示安装,按提示安装,可能会出错,可进.

willhu2008的专栏 2万+

mysql 计算不同胜率的活跃玩家的次日,3日,7日留存率

它根据每天的日期(logymd)和最高段位(max_rank)、胜率段落(win_rate_segment)进行分组,并计算总玩家人数(total_players)、第二天的留存人数(next_day_players)、第三天的留存人数(day3_players)和第七天的留存人数(day7_players)。注意:不是新手留存,是段位活跃玩家留存;最终的结果则是将留存数据进行展示,按照日期(date)、最高段位(rank_level)、胜率段落(win_rate_segment)进行排序。

weixin_42698221的博客 1836

基于FPGA的CORDIC算法实现——Verilog版

目前,学习与开发FPGA的程序员们大多使用的是Verilog HDL语言(以下简称为Verilog),关于Verilog的诸多优点一休哥就不多介绍了,在此,我们将重点放在Verilog的运算操作上。 我们都知道,在Verilog中,运算一般分为逻辑运算(与或非等)与算术运算(加减乘除等)。而在一开始学习Verilog时,老司机一定会提醒我们,“切记,千万别用‘/’除、‘%’取模(有的也叫取余)和‘

善良の一休君的博客 6万+

ZYNQ microblaze boot.bin固化步骤

一,ZYNQ移植软核的原理FPGA规模巨大而且功能复杂,因此设计的每一个部分都从头开始是不切实际的。一种解决的办法是:对于较为通用的部分可以重用现有的功能模块,而把主要的时间和资源用在设计中的那些全新的、独特的部分。这就像是你在开发应用程序的时候就不用直接去写驱动物理硬件的代码,而是直接调用Windows提供的API就行了。

wangjie36的博客 2781

运行codex时出现登录失败:failed to start login server: 以一种访问权限不允许的方式做了一个访问套接字的尝试。 (os error 10013) 解决方案

的本质是Windows 系统端口保留策略而非代码 bug。推荐使用方案一(调整动态端口范围),一劳永逸解决。如果你安装了 Docker Desktop 或启用了 WSL2,调整端口范围后记得检查相关服务是否正常运行。

一键难忘的博客 4154

FM20S用户手册--Linux系统启动卡制作及系统固化

评估板出厂时,默认提供一张配套的Micro SD卡,此卡为可正常使用的Linux系统 启动卡。评估板断电,将Linux系统启动卡插入评估板Micro SD卡槽,根据评估底板丝印将 启动方式选择拨码开关拨为1010(1-4).此档位为Micro SD启动模式。使用Linux 系统启动卡启动系统时,将使用此目录的BOOTbn文件启动FSBL和U-Boot。Linux系统启动卡制作时,已将固化系统的脚本文件mkemmcboot.sh拷贝至Linux系 统启动卡文件系统的"/opt/tools/"目录下。

创龙,嵌入式一体化解决方案商 301

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

上一篇: 10个人9个答错,另外1个只对一半:数据库的锁,到底锁的是什么?
下一篇: Java Record 的一些思考 - 序列化相关
superjava_
博客等级 码龄5年 254粉丝 81原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值