扫描下方二维码或者微信搜索公众号
菜鸟飞呀飞
,即可关注微信公众号,阅读更多Spring源码分析
和Java并发编程
文章。
微信公众号
问题
本文内容是接着前两篇文章写的,有兴趣的朋友可以先去阅读下两篇文章: Netty 源码分析系列之服务端 Channel 初始化 和 Netty 源码分析系列之服务端 Channel 注册
由于 Netty 是对 JDK 原生 NIO 的封装,对比 JDK 原生 NIO 的写法,我们可以先思考一下以下两个问题。
-
在 JDK 原生 NIO 写法中,会调用 serverSocketChannel.bind(new InetSocketAddress(port)) 进行端口号的绑定,那么在 Netty 中,绑定端口号的操作又是在什么地方实现的呢?
-
在 JDK 原生的 NIO 写法中,在将 ServerSocketChannel 注册到多路复用器 Selector 上时,就将 ServerSocketChannel 感兴趣的事件设置为了 OP_ACCEPT 事件,而 Netty 中,将 channel 注册到 Selector 时,将 channel 感兴趣的事件设置的是 0 ,即对任何事件都不感兴趣。那么在 Netty 中,又是什么时候将服务端 channel 感兴趣的事件设置为 OP_ACCEPT 的呢?
JDK 原生 NIO 的写法如下。
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 轮询器,不同的操作系统对应不同的实现类
Selector selector = Selector.open();
// 绑定端口
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
// 将服务端channel注册到轮询器上,并告诉轮询器,自己感兴趣的事件是ACCEPT事件
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
端口绑定
当调用 serverBootstrap.bind(port) 时,会调用到 AbstractBootstrap.doBind(final SocketAddress localAddress) 方法。在 doBind(localAddress) 方法中,会先调用 initAndRegister() 方法来初始化服务端 Channel 以及将服务端 channel 注册到多路复用器上,该方法详细的源码分析已经在前两篇文章中Netty 源码分析系列之服务端 Channel 初始化 和 Netty 源码分析系列之服务端 Channel 注册 分析过了,今天将接着分析 doBind(localAddress) 后面的逻辑。doBind(localAddress)方法的源码如下
private ChannelFuture doBind(final SocketAddress localAddress) {
//初始化和注册
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
// 无论是进入if还是进入else,最终均会执行doBind0()
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
// Registration future is almost always fulfilled already, but just in case it's not.
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelF