NOTE

2.75 4.服务端口绑定

调用 bind - doBind - initAndRegister - channelFactory.newChannel() - init(channel) - ChannelFuture regFuture = config().group().register(channel); - doB

Java创建于 更新于 historical

这是历史学习笔记,可能存在过时或不完整的理解。

调用

bind

  • doBind
  • initAndRegister
  • channelFactory.newChannel()
  • init(channel)
  • ChannelFuture regFuture = config().group().register(channel);
  • doBind0(regFuture, channel, localAddress, promise);我们重点看这个

AbstractBootstrap

private static void doBind0(
        final ChannelFuture regFuture, final Channel channel,
        final SocketAddress localAddress, final ChannelPromise promise) {

    // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up
    // the pipeline in its channelRegistered() implementation.
    channel.eventLoop().execute(new Runnable() {
        @Override
        public void run() {
            if (regFuture.isSuccess()) {
            	//调用AbstractChannel的bind
            	//接着调用DefaultChannelPipeline的bind
            	//再调用AbstractChannelHandlerContext#bind
            	//最后来到AbstractChannel.AbstractUnsafe#bind
                channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            } else {
                promise.setFailure(regFuture.cause());
            }
        }
    });
}

AbstractUnsafe

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

	//调用jdk底层绑定地址
	//javaChannel().bind(localAddress, config.getBacklog());
    doBind(localAddress);


    if (!wasActive && isActive()) {
        invokeLater(new Runnable() {
            @Override
            public void run() {
            	//调用pipeline上所有InboundHandler的channelActive方法
            	//第一个handler为DefaultChannelPipeline.HeadContext
                pipeline.fireChannelActive();
            }
        });
    }

    safeSetSuccess(promise);
}

io.netty.channel.DefaultChannelPipeline.HeadContext#channelActive

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

    readIfIsAutoRead();//关键
    //会调用channel.read->pipeline.read->tail.read->ChannelOutboundHandler.read->
    //io.netty.channel.AbstractChannel.AbstractUnsafe#beginRead
    //->io.netty.channel.nio.AbstractNioChannel#doBeginRead
}

AbstractNioChannel

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

    readPending = true;

    final int interestOps = selectionKey.interestOps();
    if ((interestOps & readInterestOp) == 0) {
    	//增加读事件:accpet事件
        selectionKey.interestOps(interestOps | readInterestOp);

    }
}