文档章节

小白带你认识netty(二)之netty服务端启动(下)

天空小小
 天空小小
发布于 11/18 23:20
字数 1546
阅读 9
收藏 0

承接上一篇小白带你认识netty(二)之netty服务端启动(上),还剩下两步骤:3、注册Selector:将Channel注册到Selector上 和 4、端口的绑定:服务端端口的监听。

3、注册Selector:将Channel注册到Selector上

分析完init方法,继续分析ChannelFuture regFuture = config().group().register(channel);

看下config方法,本对象中该方法是abstract,即调用子类的config方法,因为AbstractBootstrap的子类的是ServerBootstrap,因此进入ServerBootstrap看下:

那么问题来了,这个config是在哪初始化的呢?

原来是定义的时候就已经初始化了。看下该类的group方法:

原来还是调用AbstractBootstrap类的group方法,我们知道,这里的group是bossEventLooGroup,还记的吗?不记得就再看一便上一章哦。。因此这个register方法是调用的NioEventLoopGoup类里的register方法。因为NioEventLoopGoup没有该register方法,所以就调用了其父类MultithreadEventLoopGroup类中的register方法。

看下这个next方法,

跟进父类的next方法:

看下这个chooser是啥?

还记得第一章中的EventLoop数组的选择器么?有划红线强调的哦。。。此next方法就是在NioEvenetLoopGroup中的EventLoop数组中选出一个EventLoop对象来。因此此处的register方法应该是EventLoop中的方法。因为EventLoop没有该方法,即调用父类SingleThreadEventLoop的register方法。

这里unsafe方法很明显是调用NioServerSocketChannel中的unsafe方法。继续跟进:

还记的这个unsafe的初始化么?就是在AbstractChannl的构造方法中初始化的,下图证:

所以register方法是DefaultServerUnsafe类中的,因为该类没有register方法,所以调用的是该类的父类AbstractUnsafe类中的方法:

首先通过AbstractChannel.this.eventLoop = eventLoop;将线程绑定到了NioServerSocketChannel上,即NioServerSocketChannel实例化了eventLoop。因此上一章的:

这里ch.eventLoop就不为null了。继续eventLoop的inEventLoop,一直向NioEventLoop的父类上追,追到了AbstractEventExecutor类,看下该类的inEventLoop:

继续跟进:

thread是当前线程,那this.thread是啥???因为我们在分析NioEventLoop并没有看到这个this.thread的实例化,所以这里是null,因此这个条件返回false,走的else的逻辑。

看下这个eventLoop.execute方法:

同理,inEventLoop返回的是false,所以,应该是走else的逻辑:

使用cas无锁化执行doStartThread()方法。

这个executor是哪来的?我们在分析NioEventLoopGroup的时候,知道了会初始化一个线程执行器:

因此executor是执行的ThreadPerTaskExecutor类里的execute方法:

因此executor.execute是创建一个线程执行run方法。在上面的run方法中,thread = Thread.currentThread();将当前的线程赋值给了NioEventLoop对象的thread变量,因此只要是该NioEventLoop对象的inEventLoop方法都是返回的true了。注意是NioEventLoop而不是NioEventLoopGroup。接着就是执行SingleThreadEventExecutor.this.run();方法了,这个方法我们后面会分析,这里不做分析。再次回到

这个方法上,暂时我们只要知道startThread是为NioEventLoop创建一个线程。在多说一句,这个线程是一直处于循环状态的。我们继续看addTask方法:

这个方法很简单,就是将task丢进队列中,如下图:

这个taskQueue没有忘吧,就是netty优化的mpsc队列。OK既然把register0方法的调用放在了taskQueue中,总之会被调用的,看下register0:

先看下doRegister方法:

这里的javaChannel就是jdk原生的ServerSocketChannel对象了。所以真相就在这里,这里是原生的jdk注册方法,将ServerSocketChannel注册到NioEventLoop的select上,注意第三个参数为0.

至此注册selector过程结束。

4、端口的绑定

回到doBind方法:

以上三步分析完了initAndRegister方法,继而我们进入doBind0这个方法。

有了上面的基础,我们很容易知道调用的NioEvenetLoop对象的execute方法,即将该run方法放入到NioEventLoop的taskQueue中,最终被执行。

下面分析下channel.bind方法,系好安全带,因为没有pipeline的知识点,所以会感觉开车比较快。

调用NioServerSocketChannel的bind方法,

继续跟进:

继续:

继续跟进:next.invokeBind(localAddress, promise);

继续跟进,就是HeadContext中的bind方法:

看下这个unsafe是啥?

就是NioServerSocket中的NioMessageUnsafe,即调用的还是AbstractUnSafe类中的方法:

进入doBind方法:

至此,绑定的代码就真相大白了,就是调用了jdk原生的bind方法。

这里还有一个小点,之前看到的,向selector注册的事件是0啊,并没有注册accept事件啊。。这里,我们回到bind方法:

分析完了了doBind方法,我们继续向下看:

这里会执行pipeline.fireChannelActive();方法,跟进去,同样系好安全带哦:

继续:

继续跟进next.invokeChannelInactive();

这里的channelInactive会调用HeadContext类的channelInactive方法:

第一个方法,则是调用ChannelActive事件,后面详细说。这里我们重点下面的方法:readIfIsAutoRead。

继续:

继续跟进read:

继续跟进:

继续:

然后跟进invokeRead方法:

然后调用HeadContext的read方法:

卧槽,绕了一堆,还是调用AbastractUnSafe的beginRead方法:

继续跟进doBeginRead方法:

还记得这个selectionKey么?就是上面红字强调的:

再向selector注册NioServerSocket的时候,注册的事件是0,因此if ((interestOps & readInterestOp) == 0)这个判断返回的是true。那么readInterestOp这个哪来的?还记的上一章的accept事件么?

一次次调用父类方法,放在AbstractNioChannel类里面了。因此:

这里的逻辑就是向selector注册accept事件。

OK,到这里,netty的启动过程就分析完了,虽然中间有些方法还不清楚何时被触发,但总是知道一个启动流程了。总结下这启动步骤:

newChannel():创建NioServerSocketChannel对象

init():初始化NioServerSocketChannel对象

register():向Selector中注册NioServerSocketChannel对象

doBind():对本地端口进行监听,监听成功后,重新向selector注册OP_ACCEPT事件。

© 著作权归作者所有

共有 人打赏支持
天空小小
粉丝 2
博文 29
码字总数 39213
作品 0
南京
程序员
私信 提问
小白带你认识netty(二)之netty服务端启动(上)

上一章 中的标准netty启动代码中,ServerBootstrap到底是如何启动的呢?这一章我们来瞅下。 启动代码无非这么几行,我一行一行的瞅。 server.group(bossGroup, workGroup); 还记得上一章定义...

天空小小
11/18
0
0
Netty入门-client/server

一、环境准备 开发工具eclipse/idea(本人目前正在切换为idea),maven插件 最新版的netty包maven依赖 <dependency> 二、简单的client/server demo 功能:client端发送一个“query time orde...

dkz
2015/12/09
232
0
Netty干货分享:京东京麦的生产级TCP网关技术实践总结

1、引言 京东的京麦商家后台2014年构建网关,从HTTP网关发展到TCP网关。在2016年重构完成基于Netty4.x+Protobuf3.x实现对接PC和App上下行通信的高可用、高性能、高稳定的TCP长连接网关。 早期...

JackJiang2011
2017/12/01
0
0
从零开始学netty——开启客户端

[从零开始学netty——第一个netty程序][1] [从零开始学netty——认识decoder][2] 通过上面两篇文章,大家基本了解了一个netty的样子,为了专注介绍,特意省去了客户端的编写,使用telnet来当...

xpbob
05/02
0
0
Netty源码:从一个简单Demo开始

最近在看闪电侠的《Netty深入剖析》,记录总结。 一.Netty简单示例 首先先看一个简单的HelloWord:Server.java 和 ServerHandler.java Server.java 启动Server,运行结果如下: 二.Netty是对...

Jacktanger
07/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

什么是以太坊DAO?(二)

Decentralized Autonomous Organization,简称DAO,以太坊中重要的概念。一般翻译为去中心化的自治组织。 在上一节中,我们为了展示什么是DAO创建了一个合约,就像一个采用邀请制的俱乐部,会...

geek12345
20分钟前
1
0
全屋WiFi彻底无死角 这才是终极解决方案

无线网络现在不仅在家庭中不可或缺,在酒店、医院、学校等场景中的需求也越来越多。尤其是这些场景中,房间多但也需要每个房间都能够完美覆盖WiFi,传统的吸顶式AP就无法很好的解决问题。 H3...

linux-tao
33分钟前
3
0
Python日期字符串比较

需要用python的脚本来快速检测一个文件内的二个时间日期字符串的大小,其实实现很简单,首先一些基础的日期格式化知识如下 复制代码 %a星期的简写。如 星期三为Web %A星期的全写。如 星期三为...

dragon_tech
34分钟前
3
0
ORA 各种oraclesql错误

ORA-00001: 违反唯一约束条件 (.) ORA-00017: 请求会话以设置跟踪事件 ORA-00018: 超出最大会话数 ORA-00019: 超出最大会话许可数 ORA-00020: 超出最大进程数 () ORA-00021: 会话附属于其它某...

青峰Jun19er
38分钟前
3
0
没错,老板让我写个 BUG!

前言 标题没有看错,真的是让我写个 bug! 刚接到这个需求时我内心没有丝毫波澜,甚至还有点激动。这可是我特长啊;终于可以光明正大的写 bug 了🙄。 先来看看具体是要干啥吧,其实主要就是...

crossoverJie
51分钟前
96
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部