阅读 103

Netty中BossGroup与WokerGroup协同工作—源码简要分析

1.BossGroup与WorkerGroup简单示意图如下:



2.首先搞清楚BossGroup和WorkerGroup中Channel分别如何产生与注册到Group中去的?


3.BossGroup中的Channel是何时以及如何创建的?

    (1) 在ServerBootstrap.bind()绑定相应的地址时,会根据传入的channelClass类创建对应的ChannelFactory,在ServerBootstrap.initAndRegister()方法中

        使用ChannelFactory反射实例化NioServerSocketChannel。

    (2)初始化NioServerSocketChannel实例之后传入到ServerBootStrap.init(Channel)  

         设置Channel初始化值,如ChannelOptions,Attributes。

        还有利用ChannelInitializer 将原始初始化ChannelHandler加入到Pipeline中
关键也加入了对于新channel接受动作。

       这边是利用一个ServerBootstrapAcceptor来监听channelRead事件,将新产生的channel绑定到childGroup (workerGroup),最终是绑定到WorkerGroup中某个EventLoop 中去。



4.BossGroup中的Channel是如何注册到BossGroup中的?

在以上初始化好NioServerSocketChannel之后,进行注册。config().group()其实是返回的parent group,即在我们初始化时,传入的BossGroup。


注:这边再详细说一下绑定过程

group().register(),其实通过代码跟进,它会通过Group中一个next()方法选择NioEventLoopGroup中一个NioEventLoop来具体进行绑定一个Channel对象。因为一个channel只能对应一个Eventloop。

SingleThreadEventLoop中 绑定关键代码如下:

public ChannelFuture register(final ChannelPromise promise) 
{
    ObjectUtil.checkNotNull(promise, "promise");
    promise.channel().unsafe().register(this, promise);
    return promise;
}复制代码

可以看最终是调用Channel对象下的一个内部类UnSafe对象进行完成注册。

最终的注册动作是将真正的jdk channel绑定到的EventLoop中的Selector中去。每个channel绑定到Selector中之后,就会形成一个SelectionKey,会加入到EvenLoop中的keyset集合中去。方便在循环遍历时检查每个channel的状态。



5.WorkerGroup中的Channel是何时以及如何创建的?

在BossGroup启动之后,对应的NioEventLoopGroup线程池的NioEventLoop线程就会死循环检查已经绑定到对应的Selector上的Channel的I/O事件。

(1)当没有发生I/O事件时,NioEventLoop线程会一直堵塞在selector.select() 该方法上


(2)一旦有I/O过来之后,就会调用processSelectedKeys()去处理,循环检查SelectedKeys中的每个key,再进入processSelectedKey()。

(3)再调用对应发送符合事件的channel的unsafe.read() 方法。再该方法中会创建对应NioSocketChannel对象。


6.WorkerGroup中的Channel是如何注册到WorkerGroup中的?

从上面的小点中可以看出在NioServerSocketChannel发生了I/O事件中初始化了NioSocketChannel对象,下面就是需要将该对象中是如何注册到WorkerGroup中的解释了。

因为在创建NioServerSocketChannel实例是我们在其Pipeline中添加了ServerBootstrapAcceptor的InboundChannelHandler。并且如下图所示,在创建完Channel之后又将会会NioServerSocketChannel的Pipeline的channelread方法。这样在ServerBootstrapAcceptor中的channelread方法也会得到相应的触发。


这样在ServerBootStrap中的ServerBootstrapAcceptor中
的channelRead就会触发,将新生成的channel注册到ChildGroup中去。接下来就会由WorkGroup的EventLoop对channel进行管理。


7.对SevrerBootstrapAcceptor类简单概述

SeverBootstrapAcceptor也是一个Inbound处理器,用于Server端accept新的客户端连接时,向新生成的socketChannel中添加用户定义的业务处理器。且将新生成的socketChannel注册到WorkerGroup中去。

8.对UnSafe类简单概述

Unsafe是Channel的内部类,一个Channel对应一个UnSafe。
UnSafe用于处理Channel对应网络IO的底层操作。ChannelHandler处理回调事件时产生的相关网络IO操作最终也会委托给UnSafe执行。

UnSafe接口中定义了socket相关操作,包括SocketAddress获取、Selector注册、网卡端口绑定、socket建联与断连、socket写数据。

其实workgroup与bossgroup在监听I/O事件逻辑是一样(本身就是同一块代码实现),为什么会有不同read效果呢。从上面的分析,BossGroup会通过UnSafe.read()会有Channel实例产生,但是如果是wokergroup就不是这样的。

为什么呢?

那是因为NioServerSocketChannel 和 NioSocketChannel内部对unsafe的实现不一样。次啊会有此区别。每次与socket的交互还是会通过对应channel的unsafe类进行的。这样虽然BossGroup和Woke人Group共享NioEventLoop代码,但是由于其使用的Channel类型对应的UnSafe实现不一样才会导致对read方法调用有不一样的行为。



Bossgroup : 

NioMessageUnsafe ---> AbstractNioMessageChannel、NioServerSocketChannel


Workergroup :

NioByteUnsafe ---> AbstractNioByteChannel、NioSocketChannel