本文基于netty-all:4.1.6.Final版本进行简略分析,如有不对,感谢指出。
初次接触netty,网上发现一张比较好的线程模型,如图1
图1
从图1中可以看出,抛开细节,整个netty的运转是类似于java线程池,不断地执行任务队列中的任务,后面源码中会分析,线程池的继承关系。
下面就按照图1进行一步步分析,我们服务端常见的启动代码如下:
1 | scss复制代码 public void start(InetSocketAddress address){ |
1. BossGroup初始化工作
NioEventLoopGroup的继承关系如下
可以看出group其实最顶层服务类Exector,那么其必然是通过线程对各种任务进行管理。
在其父类MultithreadEventLoopGroup构造函数中,如果不传值,就采用默认2cpu数量
1 | java复制代码protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) { |
在向上MultithreadEventExecutorGroup类中,其构造函数如下:
1 | ini复制代码protected MultithreadEventExecutorGroup(int nThreads, Executor executor, |
NioEventLoop的参数就可以看到,图1中的Selector和TaskQueue
到这里基本就看到taskQueue和selector如何传入。
2. 服务端channel初始化和注入到eventloop
由图1可知道,channel和某一个eventloop是一一对应的关系,服务端初始化好了,那下面就看看channel是如何绑定到eventloop的,直接从bind接口入手,找到AbstractBootstrap的initAndRegister方法。
1 | scss复制代码final ChannelFuture initAndRegister() { |
2.1 init方法
看下初始化方法做了啥,
1 | scss复制代码@Override |
从上面可以,init方法,就是将读写的event loop加载进来,待触发任务回调ServerBootstrapAcceptor的read方法,不断轮询监听scoket事件
2.1 register方法
init方法并没有触发监听任务,由此可以大体猜测到
将服务端channel注册到event loop即可实现监听。由bootstrap初始化可知,其eventloop为NioEventLoop,AbstractChannel的register方法
1 | arduino复制代码@Override |
首次启动,会执行eventLoop的execute方法,看下实现SingleThreadEventExecutor.execute
1 | scss复制代码@Override |
startThread是采用cas来保证并发安全的
1 | csharp复制代码private void startThread() { |
然后能看到nioeventloop的run方法是个死循环
1 | scss复制代码@Override |
此时可以看到nioeventloop 就是处理socket时间以及处理nioeventloop添加的任务,
看下runtask里面做了啥,前面看下register里面的eventLoop.execute添加了一个任务,即register0。我们可以看下register0干了啥
1 | scss复制代码private void register0(ChannelPromise promise) { |
TestHander如下:
1 | java复制代码public class TestHander implements ChannelHandler { |
最后服务端通道只有一个channelHandle没执行,就是ServerBootstrapAcceptor
这个在有socket事件的时候才会触发
1 | scss复制代码private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) { |
3. 服务端channel绑定address
上面分析完后,最后服务端绑定sserversocket即可。
1 | arduino复制代码private static void doBind0( |
本文转载自: 掘金