netty服务端代码分析
服务端启动配置
- 对于ServerBootstrap:ServerBootstrap继承于AbstractBootstrap,它从父类继承了EventLoopGroup group,ChannelFactory extends C> 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线程模型