netty源码阅读之服务器启动之端口绑定

端口绑定,大部分是在AbstractChannel的内部类AbstractUnsafe的bind()这个方法里面完成的。主要完成了两件事情:

1、调用jdk底层绑定端口

2、传播channelActive事件。

在AbstractBoostrap的

doBind()这个方法的initAndRegister()调用后面,有一个doBind0(),一层一层进去,到达AbstractChannelHeadContext的这个方法:
    private void invokeBind(SocketAddress localAddress, ChannelPromise promise) {
        if (invokeHandler()) {
            try {
                ((ChannelOutboundHandler) handler()).bind(this, localAddress, promise);
            } catch (Throwable t) {
                notifyOutboundHandlerException(t, promise);
            }
        } else {
            bind(localAddress, promise);
        }
    }

点击HeadContext的实现,再进去一层就能看到AbstractUnsafe的bind的实现:

 public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
            assertEventLoop();

            if (!promise.setUncancellable() || !ensureOpen(promise)) {
                return;
            }

            // See: https://github.com/netty/netty/issues/576
            if (Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) &&
                localAddress instanceof InetSocketAddress &&
                !((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress() &&
                !PlatformDependent.isWindows() && !PlatformDependent.isRoot()) {
                // Warn a user about the fact that a non-root user can't receive a
                // broadcast packet on *nix if the socket is bound on non-wildcard address.
                logger.warn(
                        "A non-root user can't receive a broadcast packet if the socket " +
                        "is not bound to a wildcard address; binding to a non-wildcard " +
                        "address (" + localAddress + ") anyway as requested.");
            }

            boolean wasActive = isActive();
            try {
                doBind(localAddress);
            } catch (Throwable t) {
                safeSetFailure(promise, t);
                closeIfClosed();
                return;
            }

            if (!wasActive && isActive()) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.fireChannelActive();
                    }
                });
            }

            safeSetSuccess(promise);
        }

看NioServerSocketChannel的doBInd的实现:

 @Override
    protected void doBind(SocketAddress localAddress) throws Exception {
        if (PlatformDependent.javaVersion() >= 7) {
            javaChannel().bind(localAddress, config.getBacklog());
        } else {
            javaChannel().socket().bind(localAddress, config.getBacklog());
        }
    }

就是调用jdk底层实现端口绑定了。

观察到这一段:

if (!wasActive && isActive()) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.fireChannelActive();
                    }
                });
            }

wasActive实在doBind()之前赋值,这段代码的意思是:如果doBInd之前isActive为false,之后isActive()为true,那么就传播事件。也就是,之前没有传播过,后面绑定端口完成之后,就开始传播。

一样的道理,我们层层进入fireChannelActive最后到达HeadContext的channelAcitve方法:

    @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelActive();

            readIfIsAutoRead();
        }

这里又做了两件事:

1、传播事件

2、把在用户代码注册的读事件注册上去。

在传播事件这件事情上,我们一层一层点进去,在AbstractChannelContextHandler的这个方法里面:

    private void invokeChannelActive() {
        if (invokeHandler()) {
            try {
                ((ChannelInboundHandler) handler()).channelActive(this);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            fireChannelActive();
        }
    }

channelActive这个方法,找我们用户代码自己实现的channelActive,就能看到这个:

 @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("channelActive");
    }

是不是很神奇!!

在把在用户代码注册的读事件注册上去这里,点击进去readIfIsAutoRead()这个方法,还是实现HeadContext的read方法,AbstractNioChannel的doBegainRead()方法:

  @Override
    protected void doBeginRead() throws Exception {
        // Channel.read() or ChannelHandlerContext.read() was called
        final SelectionKey selectionKey = this.selectionKey;
        if (!selectionKey.isValid()) {
            return;
        }

        readPending = true;

        final int interestOps = selectionKey.interestOps();
        if ((interestOps & readInterestOp) == 0) {
            selectionKey.interestOps(interestOps | readInterestOp);
        }
    }

可以很容易知道,readInterestOps就把读事件传递进去了。

猜你喜欢

转载自blog.csdn.net/fst438060684/article/details/81431560