切片Netty-doBind0

Netty源码分析基于主流的Netty4.x版本。
承接上篇的initAndRegister,本篇主要看看bind方法里面doBind0逻辑。

一.绑定地址

    private static void doBind0(
            final ChannelFuture regFuture, final Channel channel,
            final SocketAddress localAddress, final ChannelPromise promise) {
        channel.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                if (regFuture.isSuccess()) {
                	// CLOSE_ON_FAILURE监听事件是ChannelFuture失败时,执行关闭channel操作
                    channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    promise.setFailure(regFuture.cause());
                }
            }
        });
    }

进入bind方法,沿着调用链,来到AbstractChannelHandlerContext的bind方法。

	public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
        ...
        // 向前查找下一个ChannelOutboundHandler类型的处理器,这里是从TailConetxt向前查找
        final AbstractChannelHandlerContext next = findContextOutbound();
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeBind(localAddress, promise);
        } else {
            safeExecute(executor, new Runnable() {
                @Override
                public void run() {
                    next.invokeBind(localAddress, promise);
                }
            }, promise, null);
        }
        return promise;
    }

按照demo中的设置,当前pipelien中只存在HeadContext,ServerBootstrapAcceptor,TailContext处理器,其中HeadContext即是输入也是输出处理器,ServerBootstrapAcceptor是输入处理器,TailContext为输出处理器。

findContextOutbound方法向前查找的获取的是HeadContext。

继续追踪,来到AbstractChannel的bind方法

    public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
            assertEventLoop();
			...
			// 目前还未激活,返回false
            boolean wasActive = isActive();
            try {
            	// 这里调用原生的channel进行绑定操作,激活成功
                doBind(localAddress);
            } catch (Throwable t) {
               ...
                return;
            }
            if (!wasActive && isActive()) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                    	// fireChannelActive方法传递激活事件
                    	// 从header开始依次向ChannelInboundHandler类型的处理器传递
                        pipeline.fireChannelActive();
                    }
                });
            }
			// 更新promise为成功状态
            safeSetSuccess(promise);
        }

当前的channel为NioServerSocketChannel,故查看里面的doBind方法。

   protected void doBind(SocketAddress localAddress) throws Exception {
   		// 实际执行jdk的chanel绑定操作
        if (PlatformDependent.javaVersion() >= 7) {
        	// Backlog这个是设置最多可以进行连接的数量
            javaChannel().bind(localAddress, config.getBacklog());
        } else {
            javaChannel().socket().bind(localAddress, config.getBacklog());
        }
    }

二.传递激活事件

绑定成功之后,isActive方法会返回true,接下来看看传播激活事件的操作

	public final ChannelPipeline fireChannelActive() {
		// 激活传播首先从HeadContext开始
        AbstractChannelHandlerContext.invokeChannelActive(head);
        return this;
    }

进入HeadContext的invokeChannelActive方法

	private void invokeChannelActive() {
		// 当前处理器如果已经放入pipeline中返回true
        if (invokeHandler()) {
            try {
            	//  handler()返回当前的对象即HeadContext
                ((ChannelInboundHandler) handler()).channelActive(this);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            fireChannelActive();
        }
    }

HeadContext的channelActive主要做两件事:

  1. 继续传播激活事件
  2. 设置SelectionKey对OP_ACCEPT感兴趣
  public void channelActive(ChannelHandlerContext ctx) {
  			// 继续传播激活事件
            ctx.fireChannelActive();

            readIfIsAutoRead();
        }

1. 传播激活事件
findContextInbound方法是向查找下一个ChannelInboundHandler类型的处理器。

   public ChannelHandlerContext fireChannelActive() {
        invokeChannelActive(findContextInbound());
        return this;
    }

2.设置interestOps

	private void readIfIsAutoRead() {
			// 这里默认为true
            if (channel.config().isAutoRead()) {
                channel.read();
            }
        }

沿着调用链继续走,来到TailContext的read方法。

	public ChannelHandlerContext read() {
		// 这里还是先前先前查找,按照当前的上下文情况,会找到HeadContext
        final AbstractChannelHandlerContext next = findContextOutbound();
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeRead();
        } else {
            Tasks tasks = next.invokeTasks;
            if (tasks == null) {
                next.invokeTasks = tasks = new Tasks(next);
            }
            executor.execute(tasks.invokeReadTask);
        }

        return this;
    }

HeadContext的invokeRead只是中转下,最终调用AbstractChannel的beginRead方法。

	public final void beginRead() {
           ...
            try {
                doBeginRead();
            } catch (final Exception e) {
                ...
            }
        }

由于当前channel为NioServerSocketChannel,故最终调用AbstractNioChannel的doBeginRead

	protected void doBeginRead() throws Exception {
        final SelectionKey selectionKey = this.selectionKey;
        if (!selectionKey.isValid()) {
            return;
        }
        readPending = true;
		// interestOps 这里之前设置0
        final int interestOps = selectionKey.interestOps();
        // 在实例化NioServerSocketChannel中设置了readInterestOp为SelectionKey.OP_ACCEPT
        if ((interestOps & readInterestOp) == 0) {
        	// 最终对SelectionKey.OP_ACCEPT事件感兴趣
            selectionKey.interestOps(interestOps | readInterestOp);
        }
    }

三. 总结

至此,服务端启动完成,创建了了一个NioServerSocketChannel,关联的selector关注新连接事件。当有新连接来临,将会触发OP_ACCEPT事件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值