您好,登录后才能下订单哦!
https://blog.51cto.com/483181/2121265
我们继续分析doBind0(regFuture, channel, localAddress, promise)
 private ChannelFuture doBind(final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }
        if (regFuture.isDone()) {
            // At this point we know that the registration was complete and successful.
            ChannelPromise promise = channel.newPromise();
            doBind0(regFuture, channel, localAddress, promise); //3. 我们这篇要分析的内容
            return promise;
        } else {
            ...
            return promise;
        }
    }如上面代码,doBind0有4个参数regFuture, channel, localAddress, promise,它们的类型如下:
regFuture: DefaultChannelPromise
channel:NioServerSocketChannel
localAddress:SocketAddress
promise:DefaultChannelPromise
那继续往下面看代码,
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()) {
                    channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    promise.setFailure(regFuture.cause());
                }
            }
        });
    }doBind0()代码很简单,调用channel.eventloop()执行了一个Runnable。channel.eventloop()调用的是AbstractChannle.eventloop()
@Override
    public EventLoop eventLoop() {
        EventLoop eventLoop = this.eventLoop;
        if (eventLoop == null) {
            throw new IllegalStateException("channel not registered to an event loop");
        }
        return eventLoop;
    }而this.eventLoop初始化是在register的时候,具体可以参考上一篇bind初始化的分析
https://blog.51cto.com/483181/2121265
@Override
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            ....
            AbstractChannel.this.eventLoop = eventLoop;
                        ...
           }                它的类型是一个NioEventLoop,所以它就是往自己的线程池里面丢了一个Runnable任务
NioEventLoop的继承关系图如下:
我们可以看一下NioEventLoop.execute(Runnable )方法.
这个方法的实现是在SingleThreadEventExecutor.java里面。
private final Queue<Runnable> taskQueue;
@Override
    public void execute(Runnable task) {
        if (task == null) {
            throw new NullPointerException("task");
        }
        boolean inEventLoop = inEventLoop();
        addTask(task);
        if (!inEventLoop) {
            startThread();
            if (isShutdown() && removeTask(task)) {
                reject();
            }
        }
        if (!addTaskWakesUp && wakesUpForTask(task)) {
            wakeup(inEventLoop);
        }
    }
protected void addTask(Runnable task) {
        if (task == null) {
            throw new NullPointerException("task");
        }
        if (!offerTask(task)) {
            reject(task);
        }
    }       
final boolean offerTask(Runnable task) {
        if (isShutdown()) {
            reject();
        }
        return taskQueue.offer(task);
    }       它是把传入的Runnable对象放到一个taskQueue队列里面。
那我们继续看Runnable里面的实现,channel.bind(xxxx)
channel.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                             ...
               channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            }
        });Channel的类型是NioServerSocketChannel,而bind方法的实现类是在AbstractChannel.java里面.
@Override
    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return pipeline.bind(localAddress, promise);
    }调用的是pipeline.bind(xxx),pipeline我们知道,它链接了ChannelHandler的Context,有head和tail。head是outbound,tail是inbound.
DefaultChannelPipeline.java
@Override
    public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return tail.bind(localAddress, promise);
    }直接调用的是tail.bind,继续往下面看
AbstractChannelHandlerContext.java
@Override
    public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
        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;
    }
private AbstractChannelHandlerContext findContextOutbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.prev;
        } while (!ctx.outbound);
        return ctx;
    }       它调用findContextOutbound(),然后调用它的bind方法,从以前的分析可以知道,outbound讲的是head。所以,我们来到head.bind方法
DefaultChannelPipeline.java
@Override
        public void bind(
                ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
                throws Exception {
            unsafe.bind(localAddress, promise);
        }调用的是unsafe.bind
AbstractChannel.java
@Override
        public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
            assertEventLoop();
            ...
            boolean wasActive = isActive();
            try {
                doBind(localAddress);
            } catch (Throwable t) {
                ...
            }
            if (!wasActive && isActive()) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.fireChannelActive();
                    }
                });
            }
            safeSetSuccess(promise);
        }继续看doBind()
doBind是在NioServerSocketChannel里面
@Override
    protected void doBind(SocketAddress localAddress) throws Exception {
        if (PlatformDependent.javaVersion() >= 7) {
            javaChannel().bind(localAddress, config.getBacklog());
        } else {
            javaChannel().socket().bind(localAddress, config.getBacklog());
        }
    }这样就调用了Java的接口绑定了我们传入的端口。
这样bind逻辑整个就分析完了,我们来分析一下整个流程以及类之间的关系。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。