59.Netty源代碼分析-ServerBootstrapbind過(guò)程-2

一. 接上一篇

https://blog.51cto.com/483181/2121265

站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到玉門(mén)網(wǎng)站設(shè)計(jì)與玉門(mén)網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名注冊(cè)、網(wǎng)絡(luò)空間、企業(yè)郵箱。業(yè)務(wù)覆蓋玉門(mén)地區(qū)。

我們繼續(xù)分析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. 我們這篇要分析的內(nèi)容
            return promise;
        } else {
            ...
            return promise;
        }
    }

二. doBind0

2.1 4個(gè)參數(shù)

如上面代碼,doBind0有4個(gè)參數(shù)regFuture, channel, localAddress, promise,它們的類型如下:
regFuture: DefaultChannelPromise
channel:NioServerSocketChannel
localAddress:SocketAddress
promise:DefaultChannelPromise

那繼續(xù)往下面看代碼,

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()代碼很簡(jiǎn)單,調(diào)用channel.eventloop()執(zhí)行了一個(gè)Runnable。channel.eventloop()調(diào)用的是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的時(shí)候,具體可以參考上一篇bind初始化的分析

https://blog.51cto.com/483181/2121265

@Override
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            ....

            AbstractChannel.this.eventLoop = eventLoop;
                        ...
           }                

它的類型是一個(gè)NioEventLoop,所以它就是往自己的線程池里面丟了一個(gè)Runnable任務(wù)
NioEventLoop的繼承關(guān)系圖如下:
59. Netty源代碼分析-ServerBootstrap bind 過(guò)程-2

我們可以看一下NioEventLoop.execute(Runnable )方法.

2.2 execute(Runnable)方法

這個(gè)方法的實(shí)現(xiàn)是在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對(duì)象放到一個(gè)taskQueue隊(duì)列里面。

那我們繼續(xù)看Runnable里面的實(shí)現(xiàn),channel.bind(xxxx)

channel.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                             ...
               channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            }
        });

2.3 channel.bind

Channel的類型是NioServerSocketChannel,而bind方法的實(shí)現(xiàn)類是在AbstractChannel.java里面.

@Override
    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return pipeline.bind(localAddress, promise);
    }

調(diào)用的是pipeline.bind(xxx),pipeline我們知道,它鏈接了ChannelHandler的Context,有head和tail。head是outbound,tail是inbound.

2.4 pipe.bind(xxx)

DefaultChannelPipeline.java

@Override
    public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return tail.bind(localAddress, promise);
    }

直接調(diào)用的是tail.bind,繼續(xù)往下面看
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;
    }       

它調(diào)用findContextOutbound(),然后調(diào)用它的bind方法,從以前的分析可以知道,outbound講的是head。所以,我們來(lái)到head.bind方法

2.5 head.bind

DefaultChannelPipeline.java

@Override
        public void bind(
                ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
                throws Exception {
            unsafe.bind(localAddress, promise);
        }

調(diào)用的是unsafe.bind

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

繼續(xù)看doBind()

2.7 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());
        }
    }

這樣就調(diào)用了Java的接口綁定了我們傳入的端口。

這樣bind邏輯整個(gè)就分析完了,我們來(lái)分析一下整個(gè)流程以及類之間的關(guān)系。

三. 總結(jié)

3.1 各個(gè)類之間的關(guān)系

  1. EventLoopGroup里面包含若干個(gè)EventLoop,具體數(shù)目我們可以手動(dòng)指定,如果不指定,一般默認(rèn)就是cpu x 2個(gè)。
  2. EventLoop繼承自SingleThreadEventLoop,表示一個(gè)線程,里面有個(gè)隊(duì)列queue,用來(lái)存丟過(guò)來(lái)的Runnable任務(wù).
  3. 我們一般實(shí)例化兩個(gè)EventLoopGroup,一個(gè)是bossGroup,一個(gè)是workGroup,bossGroup用來(lái)接收客戶端連接,連接可以用channel來(lái)描述。然后就把channel丟給workGroup,由workGroup具體負(fù)責(zé)這個(gè)channel后面的操作。

3.2 對(duì)應(yīng)關(guān)系

  1. 一個(gè)EventLoopGroup包含多個(gè)EventLoop
  2. 一個(gè)EventLoop對(duì)應(yīng)多個(gè)channel,一個(gè)channel只對(duì)應(yīng)一個(gè)EventLoop。EventLoop一般比channel少,好比飯店里面服務(wù)員一般比客人少。所以,也可以想象如果某一個(gè)channel上EventLoop做的業(yè)務(wù)邏輯比較復(fù)雜的話,有可能造成來(lái)不及相應(yīng)其他channel的請(qǐng)求。
  3. 一個(gè)NioServerSocketChannel里面包含一個(gè)pipeline,一個(gè)unsafe對(duì)象

分享標(biāo)題:59.Netty源代碼分析-ServerBootstrapbind過(guò)程-2
網(wǎng)頁(yè)URL:http://muchs.cn/article4/ijdsoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、企業(yè)網(wǎng)站制作、軟件開(kāi)發(fā)、靜態(tài)網(wǎng)站營(yíng)銷型網(wǎng)站建設(shè)、做網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

微信小程序開(kāi)發(fā)