netty源码研究一(服务端启动)


netty服务端代码分析

服务端启动配置

- 对于ServerBootstrap:ServerBootstrap继承于AbstractBootstrap,它从父类继承了EventLoopGroup group,ChannelFactory channelFactory,自己新增了EventLoopGroup childGroup,ChannelHandler childHandler。上面b.group开始的链式代码就是初始化上面这些属性的值的。 - bossgroup和workergroup:可以看到都是NioEventLoopGroup,可以理解成2个线程池。从bossgroup中随便选一个作为Reactor模型中的acceptor,监听客户端连接,创建socketChannel,然后从workergroup选取一个io线程来处理socketChannel的读取事件。 - 对于NioEventLoopGroup和NioEventLoop:先看下类图

可以看到NioEventLoopGroup继承了EventLoopGroup

NioEventLoop实现了EventLoop,而EventLoop又继承自EventLoopGroup。eventloopgroup.next()又可以返回一个eventloop。可以看到EventLoop最终继承于线程池Executor。而最终NioEventLoopGroup又实现了EventLoop,接下来我们还会分析下NioEventLoopGroup

服务端注册感兴趣事件和监听端口

注册感兴趣事件

b.bind最终调用到AbstractBootstrop的以下方法

  • final ChannelFuture initAndRegister() {
    this.group().register(channel);(中间省略)
    }这个this.group就是一开始设置的bossgroup(NioEventLoopGroup),看到这个方法基本可以想到这个应该是把channel注册到某个选择器上
  • MultithreadEventLoopGroup
    public ChannelFuture register(Channel channel) {
    return this.next().register(channel);
    }上面的类图已经可以看出NioEventLoopGroup继承自MultithreadEventLoopGroup,最终this.next()又会返回NioEventLoop,所以也就是可以理解是把channel注册到NioEventLoop上(我们猜想NioEventLoop可以想象成封装了一个selector)
  • this.next()返回NioEventLoop继承于SingleThreadEventLoop channel.unsafe().register(this, promise);最终调用到AbstractUnsafe的register方法
    eventLoop.execute(new OneTimeTask() { public void run() { AbstractUnsafe.this.register0(promise); } });
    这里通过bossgroup启动一个线程
  • 最终调用到
    protected void doRegister() throws Exception {
       boolean selected = false;
    
           while(true) {
               try {
                   this.selectionKey = this.javaChannel().register(this.eventLoop().selector, 0, this);
                   return;
               } catch (CancelledKeyException var3) {
                   if(selected) {
                       throw var3;
                   }
    
                   this.eventLoop().selectNow();
                   selected = true;
               }
           }
       }

监听端口

可以看到第四张截图

ChannelFuture regFuture = this.initAndRegister();
if(regFuture.cause() != null) {
    return regFuture;
} else if(regFuture.isDone()) {
    doBind0(regFuture, channel, localAddress, promise1); return promise1;
} else {
    AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise); } }); return promise;
}

可以看到initAndRegister()这个方法就是上面我们说的注册感兴趣的事件。后面的else if和else 都有dobind0 方法,这个方法也是通过之前的线程池启动一个线程去监听一个端口。

参考

netty api说明
Netty 4源码解析:服务端启动
Netty 4源码解析:请求处理
Netty系列之Netty线程模型


文章作者: 叶明
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 叶明 !
评论
 上一篇
netty源码研究二(请求处理) netty源码研究二(请求处理)
前言上一篇文章中,已经分析了netty的服务器端启动过程,我们知道NioEventLoop.run()方法,是服务器端用来轮询客户端的请求。我们指定创建出的NioServerSocketChannel就是注册到了NioEventLoop中的
2016-04-02
下一篇 
再见,陆金所 再见,陆金所
今天刚拿到退工单,陆金所已经成为过去了。从2月5号提出辞职,到今天,差不多一个月的时间。在这一个月里,因为确定要走,所以工作上的事情不是很多。但也并没有闲着,除了每天回去接着敲代码看看书,期间也想了很多事情。有必要总结一下这段工作经历。
2016-03-02
  目录