您好,登錄后才能下訂單哦!
本篇內(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ì)量的實用文章!
免責聲明:本站發(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)容。