溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

netty ServerBootstrap.bind方法怎么使用

發(fā)布時間:2021-12-16 16:45:05 來源:億速云 閱讀:373 作者:iii 欄目:云計算

本篇內(nèi)容介紹了“netty ServerBootstrap.bind方法怎么使用”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

我們都知道,netty是基于java nio的,那么具體的,java nio當中的一些具體元素,比如bind,selector,channel等等具體元素,在netty當中又是如何出現(xiàn)的。今天我們來找一找。

首先從ServerBootstrap.bind()方法開始。

該方法的具體實現(xiàn)在AbstractBootstrap當中,直接看到doBind方法,

final ChannelFuture regFuture = initAndRegister();

看看 initAndRegister 這里面具體干了點什么,

首先是創(chuàng)建了一個channel,并且從boss group當中分配一個進程給這個新創(chuàng)建的channel。

Channel channel;
try {
    channel = createChannel();
} catch (Throwable t) {
    return VoidChannel.INSTANCE.newFailedFuture(t);
}

然后是初始化的工作,具體內(nèi)容這里暫不深究。

try {
    init(channel);
} catch (Throwable t) {
    channel.unsafe().closeForcibly();
    return channel.newFailedFuture(t);
}

然后是注冊,首先得到一個promise,這個東西按照我的理解,就是為了異步的返回各種操作的執(zhí)行結(jié)果,后續(xù)我們會經(jīng)常見到它。然后執(zhí)行register,我們又發(fā)現(xiàn)一個很詭異的東西unsafe,
這個東西是創(chuàng)建channel的時候帶出來的,具體作用是跟java nio打交道,注入bind,register等操作,都在這里面完成,為什么弄這么個東西,目前不明,以后再說。

ChannelPromise regFuture = channel.newPromise();
channel.unsafe().register(regFuture);
if (regFuture.cause() != null) {
    if (channel.isRegistered()) {
        channel.close();
    } else {
        channel.unsafe().closeForcibly();
    }
}

然后是AbstractChannel$AbstractUnsafe.register(),第一個判斷很有意思,我們可以這樣理解,如果當前channel對應的 eventLoop 已經(jīng)在執(zhí)行了,也就是說,當前代碼已經(jīng)處在了一個子線程當中,那么直接調(diào)用 register0 方法,否則,新起一個線程執(zhí)行。

            if (eventLoop.inEventLoop()) {
                register0(promise);
            } else {
                try {
                    eventLoop.execute(new Runnable() {
                        @Override
                        public void run() {
                            register0(promise);
                        }
                    });
                } catch (Throwable t) {
                    logger.warn(
                            "Force-closing a channel whose registration task was not accepted by an event loop: {}",
                            AbstractChannel.this, t);
                    closeForcibly();
                    closeFuture.setClosed();
                    promise.setFailure(t);
                }
            }

然后我們看一下 register0 里面具體干了些什么:

            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 (!ensureOpen(promise)) {
                    return;
                }
                doRegister();
                registered = true;
                promise.setSuccess();
                pipeline.fireChannelRegistered();
                if (isActive()) {
                    pipeline.fireChannelActive();
                }
            } catch (Throwable t) {
                // Close the channel directly to avoid FD leak.
                closeForcibly();
                closeFuture.setClosed();
                if (!promise.tryFailure(t)) {
                    logger.warn(
                            "Tried to fail the registration promise, but it is complete already. " +
                                    "Swallowing the cause of the registration failure:", t);
                }
            }

首先通過promise檢查了一下當前channel的狀態(tài),然后執(zhí)行doRegister,這個方法在AbstractNioChannel當中實現(xiàn), 主要內(nèi)容如下:

selectionKey = javaChannel().register(eventLoop().selector, 0, this);

好了目前我們明確了2個問題,第一selector存在于 eventLoop 當中,具體地說,應該是在boss loop當中。第二個問題,在執(zhí)行register的時候,還沒有執(zhí)行bind。

在之后設置了promise,并通過pipeline出發(fā)了ChannelRegistered()事件。

下面再回到 AbstractBootstrap .doBind方法,第一步,初始化和注冊selector的過程都已經(jīng)完成了。

        final ChannelFuture regFuture = initAndRegister();
        final Channel channel = regFuture.channel();
        if (regFuture.cause() != null) {
            return regFuture;
        }

        final ChannelPromise promise;
        if (regFuture.isDone()) {
            promise = channel.newPromise();
            doBind0(regFuture, channel, localAddress, promise);
        } else {
            // Registration future is almost always fulfilled already, but just in case it's not.
            promise = new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE);
            regFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    doBind0(regFuture, channel, localAddress, promise);
                }
            });
        }

怎么理解上面那段代碼,尤其是 if (regFuture.isDone()) 之后的部分,我們前面提到,具體的register過程可能是在一個子線程當中執(zhí)行的,所以這里需要等待register完成,才能進行下一步bind操作。

看doBind0的實現(xiàn),這里還是直接起一個線程來執(zhí)行bind操作。

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

看 channel.bind ,方法實現(xiàn)在AbstractChannel當中,很有趣,直接通過pipeline來做這個bind。那么我們來看一下pipeline.bind,實現(xiàn)在DefaultChannelPipeline當中,我們看到的是tail.bind,那么很顯然,是要反向遍歷鏈表,最終通過head去執(zhí)行bind。那么我們看看HeadHandler.bind方法,unsafe.bind(localAddress, promise); 通過查找代碼,我們發(fā)現(xiàn), unsafe 就是最初我們創(chuàng)建的Server channel的unsafe,這是同一個東西。

我們再看一下AbstractChannel$AbstractUnsafe的bind方法,這里面涉及到一些對操作系統(tǒng)信息的讀取和判斷,然后調(diào)用了NioServerSocketChannel.doBind()方法,具體的真正的,java nio的bind操作,就在這里執(zhí)行。

最后一件事,java nio當中的channel在netty當中是怎么出現(xiàn)的。很簡單,看一下NioServerSocketChannel這個類,這個當中有一個newSocket方法,直接返回一個java 的ServerSocketChannel。

以上,我們基本達到了我們此次代碼分析的目的,搞清楚了,在netty服務器啟動的時候,具體干了些什么,

在netty當中找到了java nio當中的一些具體元素。

同時,我們找到了handler當中2個具體的event,bind和channelRegistered具體的發(fā)起時機。

另外,我們初步了解了netty提供的異步返回機制,ChannelFuture究竟是怎么工作的。

“netty ServerBootstrap.bind方法怎么使用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI