Bootstrap

Netty源码分析系列之服务端Channel的端口绑定

扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,阅读更多Spring源码分析Java并发编程文章。

微信公众号

微信公众号

问题

本文内容是接着前两篇文章写的,有兴趣的朋友可以先去阅读下两篇文章: Netty 源码分析系列之服务端 Channel 初始化Netty 源码分析系列之服务端 Channel 注册

由于 Netty 是对 JDK 原生 NIO 的封装,对比 JDK 原生 NIO 的写法,我们可以先思考一下以下两个问题。

  1. 在 JDK 原生 NIO 写法中,会调用 serverSocketChannel.bind(new InetSocketAddress(port)) 进行端口号的绑定,那么在 Netty 中,绑定端口号的操作又是在什么地方实现的呢?

  2. 在 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
;