netty源码阅读之客户端新连接之读事件的注册

上一篇文章《netty源码阅读之客户端新连接之分配线程并注册selector》这里,我们最后分析到AbstractChannel的register0()的代码:

        private void register0(ChannelPromise promise) {
            try {
                // check if the channel is still open as it could be closed in the mean time when the register
                // call was outside of the eventLoop
                if (!promise.setUncancellable() || !ensureOpen(promise)) {
                    return;
                }
                boolean firstRegistration = neverRegistered;
                doRegister();
                neverRegistered = false;
                registered = true;

                // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
                // user may already fire events through the pipeline in the ChannelFutureListener.
                pipeline.invokeHandlerAddedIfNeeded();

                safeSetSuccess(promise);
                pipeline.fireChannelRegistered();
                // Only fire a channelActive if the channel has never been registered. This prevents firing
                // multiple channel actives if the channel is deregistered and re-registered.
                if (isActive()) {
                    if (firstRegistration) {
                        pipeline.fireChannelActive();
                    } else if (config().isAutoRead()) {
                        // This channel was registered before and autoRead() is set. This means we need to begin read
                        // again so that we process inbound data.
                        //
                        // See https://github.com/netty/netty/issues/4805
                        beginRead();
                    }
                }
            } catch (Throwable t) {
                // Close the channel directly to avoid FD leak.
                closeForcibly();
                closeFuture.setClosed();
                safeSetFailure(promise, t);
            }
        }

注册完成之后isActive()已经为true了,然后我们这个是第一次注册(新连接已经接入并且注册到selector上面了所以isActive()为true),所以会进入到pipeline.fireChannelActive().点击进入,和服务端一样,最后会进入HeadContext的channelActive函数:

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

        readIfIsAutoRead();
    }

ctx.fireChannel就是继续传播事件,readInfIsAutoRead()就是注册读事件,进入:

private void readIfIsAutoRead() {
            if (channel.config().isAutoRead()) {
                channel.read();
            }
        }

channel.config().isAutoRead()就是是否自动阅读,默认是自动读取的。所以继续不停进入来到HeadContext的read方法:

   @Override
   public void read(ChannelHandlerContext ctx) {
        unsafe.beginRead();
    }

继续进入AbstractNioChannel的doBeginRead():

    @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);
        }
    }

在这一篇文章《netty源码阅读之客户端新连接之分配线程并注册selector》的最后,我们注册进去的事件是0,也就是什么也不注册,所以这里final int interestOps = selectionKey.interestOps();返回0。

然后readInterestOp这个值又是什么呢,我们回顾《netty源码阅读之客户端新连接之创建NioSocketChannel》第一段,创建AbstractNioByteChannel的时候,传入了SelectionKey.OP_READ,然后父类AbstractNioChannel的方法里面

this.readInterestOp = readInterestOp;

赋值了SelectionKey.OP_READ。所以readInterestOp就是赋值的值,查看源码是1。0&1是0,所以就相当于把readInterestOp这个读事件,注册进去了(在原来没有读事件的基础上,并且在不修改之前已有事件的基础上,把OP_READ事件注册进去)。

perfect。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值