首页 > Web开发 > 详细

netty4/5bind端口后的后续逻辑分析

时间:2016-01-07 00:59:19      阅读:763      评论:0      收藏:0      [点我收藏+]

上一章介绍了 bind的逻辑.bind执行之后,会开启监听.今天讨论一下监听 bind到端口之后,开启监听这一段逻辑 

1.首先从abstractUnsafe开始说起.可以看到,执行了dobind操作之后,紧接着执行的是 

 pipeline.fireChannelActive();
//abstractUnsafe 
@Override
public final void bind(final SocketAddress localAddress, final ChannelPromise promise) { if (!ensureOpen(promise)) { return; } // See: https://github.com/netty/netty/issues/576 if (!PlatformDependent.isWindows() && !PlatformDependent.isRoot() && Boolean.TRUE.equals(config().getOption(ChannelOption.SO_BROADCAST)) && localAddress instanceof InetSocketAddress && !((InetSocketAddress) localAddress).getAddress().isAnyLocalAddress()) { // 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) { closeIfClosed(); promise.setFailure(t); return; } if (!wasActive && isActive()) { invokeLater(new Runnable() { @Override public void run() { pipeline.fireChannelActive(); } }); } promise.setSuccess(); }

2.fireChannelActive 会执行 DefaultChannelPipeline的fireChannelActive方法.这里面有两个事件 一个是inbound的 以后是outbound的

@Override
    public ChannelPipeline fireChannelActive() {
        head.fireChannelActive();  //inbound

        if (channel.config().isAutoRead()) {
            channel.read();//outbound
        }

        return this;
    }

3.先看head的inbound事件.其实没有做什么.inbound在当前所有handler(head,tail,accecptor)中只有head继承了inbound.head里面的channelActive是一个空实现.

//DefaultChannelHandlerContext
 @Override
    public ChannelHandlerContext fireChannelActive() {
        final DefaultChannelHandlerContext next = findContextInbound();
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeChannelActive();
        } else {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    next.invokeChannelActive();
                }
            });
        }
        return this;
    }

//----2----
private void invokeChannelActive() {
        try {
            ((ChannelInboundHandler) handler).channelActive(this);
        } catch (Throwable t) {
            notifyHandlerException(t);
        }
    }

//TailHandler

@Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception { }

4.再看一下第二个事件,read. 他直接调用AbstractChannel的read,然后走到DefaultChannelPipeline的read,然后到DefaultChannelHandlerContext的read

然后走到了HeadHandler的read.最后终于到了AbstractUnsafe的beginRead方法里面.

//AbstractChannel
   @Override
    public Channel read() {
        pipeline.read();
        return this;
    }
//DefaultChannelPipeline
 @Override
    public ChannelPipeline read() {
        tail.read();
        return this;
    }
///DefaultChannelHandlerContext
@Override
    public ChannelHandlerContext read() {
        final DefaultChannelHandlerContext next = findContextOutbound();
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeRead();
        } else {
            Runnable task = next.invokeReadTask;
            if (task == null) {
                next.invokeReadTask = task = new Runnable() {
                    @Override
                    public void run() {
                        next.invokeRead();
                    }
                };
            }
            executor.execute(task);
        }

        return this;
    }
//---2---------
 private void invokeRead() {
        try {
            ((ChannelOutboundHandler) handler).read(this);
        } catch (Throwable t) {
            notifyHandlerException(t);
        }
    }
//HeadHandler
 @Override
        public void read(ChannelHandlerContext ctx) {
            unsafe.beginRead();
        }
//AbstractUnsafe
@Override
        public void beginRead() {
            if (!isActive()) {
                return;
            }

            try {
                doBeginRead();
            } catch (final Exception e) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.fireExceptionCaught(e);
                    }
                });
                close(voidPromise());
            }
        }

5.doBeginRead调用的是 AbstractNioChannel的实现.

//AbstractNioChannel
@Override
protected void doBeginRead() throws Exception { if (inputShutdown) { return; } final SelectionKey selectionKey = this.selectionKey; if (!selectionKey.isValid()) { return; } final int interestOps = selectionKey.interestOps(); if ((interestOps & readInterestOp) == 0) { selectionKey.interestOps(interestOps | readInterestOp); } }

 

6.最后一步

 selectionKey.interestOps()的值是之前AbastractUnsafe类中的doRegister方法执行如下代码selectionKey = javaChannel().register(eventLoop().selector, 0, this)时设置的,因此值为0。

  而readInterestOp是之前创建NioServerSocketChanne时,NioServerSocketChannel类的构造函数中设置的super(null, newSocket(), SelectionKey.OP_ACCEPT),因此值为16。

    selectionKey.interestOps(interestOps | readInterestOp)会将ops设置为16。

也就是等待 连接过来的状态了.

 

netty4/5bind端口后的后续逻辑分析

原文:http://www.cnblogs.com/wangkaick/p/5107896.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!