服务端启动代码
|
|
启动过程分析
跟踪ServerBootstrap.bind()方法,追到AbstractBootstrap.doBind():
|
|
跟踪initAndRegister()
|
|
这里先通过工厂创建了一个Channel(这里服务端指定类型NioServerSocketChannel),然后初始化这个Channel。最后把这个Channel注册到EventLoopGroup上(config().group()返回的是我们设置的Boss Group)
创建channel
查看NioServerSocketChannel构造方法
|
|
newSocket使用SelectorProvider的openServerSocketChannel打开服务器套接字通道。SelectorProvider主要工作是根据操作系统类型和版本选择合适的Provider:如果Linux内核版本>=2.6则,具体的SelectorProvider为EPollSelectorProvider,否则为默认的PollSelectorProvider
继续追溯super方法到AbstractChannel,如下方法:
|
|
这里主要做了2件事:
创建
NioMessageUnsafe实例(客户端创建NioByteUnsafe),该类为Channel提供了用于完成网络通讯相关的底层操作,如connect(),read(),register(),bind(),close()等;给该
Channel创建DefaultChannelPipeline并初始化,这里用的是默认Pipeline12345678910111213protected DefaultChannelPipeline(Channel channel) {this.channel = ObjectUtil.checkNotNull(channel, "channel");succeededFuture = new SucceededChannelFuture(channel, null);voidPromise = new VoidChannelPromise(channel, true);// 创建tailtail = new TailContext(this);// 创建headhead = new HeadContext(this);head.next = tail;tail.prev = head;}具体的
ChannelPipeline执行流程看前篇文章
到这里整个Channel创建就结束了。
总结一下:
- 通过工厂创建一个
Channel,这里的Channel由于是在服务端,使用的是NioServerSocketChannel, - 这个管道的构造方法中,会初始化一个原生的
ServerSocketChannel,最后初始化pipeline和unsafe。 - 初始化
pipeline的时候,又会初始化pipeline中的Head和Tail。
初始化channel
服务端init()实现方法在ServerBootstrap中:
|
|
服务端的init()分为2个步骤:
- 将
bootstrap配置的属性设置到Channel上面 - 给
NioServerSocketChannel的pipeline里,添加了一个ChannelHandle-ChannelInitializer,供注册后使用
初始化结束,此时NioServerSocketChannel的pipeline链表结构为:
|
|
注册channel
|
|
主要将创建并初始化后的Channel注册到selector上面:
- 将
Channel注册到EventLoop的selector上; - 触发
Pipeline上面ChannelHandler的channelRegistered
这里的config().group()结果是NioEventLoopGroup,父类是MultithreadEventLoopGroup
|
|
这里的next()方法最后执行到chooser.next(),chooser有两种:PowerOfTwoEventExecutorChooser和GenericEventExecutorChooser。如果该EventLoopGroup中EventLoop是2的倍数则选择PowerOfTwoEventExecutorChooser(2的倍数方便位操作);因为这里的Group是NioEventLoopGroup,所以next()返回的是NioEventLoop
继续看NioEventLoop.register(),具体方法实现在SingleThreadEventLoop中:
|
|
最终使用channel中的unsafe()注册,具体方法实现在AbstractUnsafe中:
|
|
invokeHandlerAddedIfNeeded: 注册成功后,找到初始化阶段通过pipeline.addLast()加入的ChannelInitializer,执行其ChannelInitializer的initChannel方法(添加ChannelHandle-ServerBootstrapAcceptor),之后将ChannelInitializer 在pipeline中删除
注册结束,此时NioServerSocketChannel的pipeline链表结构为:
|
|
fireChannelRegistered沿着pipeline的head到tail,调用ChannelHandler.channelRegistered方法
|
|
fireChannelActive 由于注册阶段和绑定bind阶段都是异步的,如果此时注册完成时bind阶段已经绑定了本地端口,会沿着pipeline的head到tail,调用各个ChannelHandler的channelActive方法
bind本地地址
将NioServerSocketChannel内部ServerSocketChannel绑定到本地的端口上面,然后调用fireChannelActive通知pipeline里的ChannelHandle,执行其channelActive方法。
|
|
AbstractBootstrap的doBind0(),内部会调用pipeline中的bind方法,逻辑为从tail出发调用outbound的ChannelHandler的bind方法。当前pipeline链表结构中只有Head是继承了outbound接口
|
|
Head的bind方法由NioServerSocketChannel创建过程中生成的unsafe的实例NioMessageUnsafe来执行,该实例的bind方法继承于AbstractUnsafe.bind(),然后触发fireChannelActive
|
|
这里的doBind(localAddress)方法由创建的NioServerSocketChannel执行
|
|
这里把java原生的ServerSocketChannel绑定到本地地址上
绑定到本地地址后会执行pipeline.fireChannelActive()方法
|
|
这里的channelInactive会调用HeadContext类的channelInactive方法:
|
|
这里首先执行fireChannelActive方法,沿着pipeline传播给后续ChannelInboundHandler,执行hannelActive()方法;接着执行readIfIsAutoRead(),可以发现这个方法作用在pipeline上,从tail到head遍历ChannelOutboundHandler执行read()方法,我们这里只有head是outBound,read()方法最后进入AbstractNioChannel.doBeginRead()
|
|
可以发现在执行doRegister()注册这个Channel到selector的时候,selectKey赋予了0
|
|
这里readInterestOp这个哪来的:在创建NioServerSocketChannel的时候
|
|
在这里重新注册了accept事件,也就是说从此开始,selector再轮询到新的连接接入事件,就可以交给这个NioServerSocketChannel来处理了
至此,Netty服务器段已经启动,Channel和ChannelPipeline已经建立,EventLoop也在不断的select()查找准备好的I/O。
总结
- 通过工厂生成
NioServerSocketChannel。 - 设置
NioServerSocketChannel对accept事件感兴趣。此时Channel已经绑定了unsafe和pipeline - 初始化
Channel,这里主要是设置Channel的pipeline中的handler、attr和option。这里的handler是特殊类型ChannelInitializer,等待注册后回调。 - 注册到
EventLoopGroup里,最终是注册到某一个NioEventLoop上面 - 在注册时实际上的
register0操作是异步的,register0的主要作用是把原生Channel注册到原生selector上。 - 执行
doBind0也是异步只想,这里其实是和register0一起在执行的。doBind0是把channel注册到本地端口上 - 执行
pipeline.read()方法,最终传递到AbstractNioChannel,重新向selector注册OP_ACCEPT事件