<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文了解Netty整體流程

          共 4895字,需瀏覽 10分鐘

           ·

          2020-12-25 09:18

          走過(guò)路過(guò)不要錯(cuò)過(guò)

          點(diǎn)擊藍(lán)字關(guān)注我們


          本文基于版本 4.1.46,同時(shí)只描述類(lèi)而不展示具體源碼。

          Netty 的整體流程

          Netty 的整體流程相對(duì)來(lái)說(shuō)還是比較復(fù)雜的,初學(xué)者往往會(huì)被繞暈。所以這里總結(jié)了一下整體的流程,從而對(duì) Netty 的整體服務(wù)流程有一個(gè)大致的了解。從功能上,流程可以分為服務(wù)啟動(dòng)、建立連接、讀取數(shù)據(jù)、業(yè)務(wù)處理、發(fā)送數(shù)據(jù)、關(guān)閉連接以及關(guān)閉服務(wù)。整體流程如下所示(圖中沒(méi)有包含關(guān)閉的部分):

          服務(wù)啟動(dòng)

          服務(wù)啟動(dòng)時(shí),我們以 example 代碼中的 EchoServer 為例,啟動(dòng)的過(guò)程以及相應(yīng)的源碼類(lèi)如下:

          1. EchoServer#new NioEventLoopGroup(1)->NioEventLoop#provider.openSelector()?: 創(chuàng)建 selector

          2. EchoServer#b.bind(PORT).sync->AbstractBootStrap#doBind()->initAndRegister()-> channelFactory.newChannel() / init(channel)?: 創(chuàng)建 serverSocketChannel 以及初始化

          3. EchoServer#b.bind(PORT).sync->AbstractBootStrap#doBind()->initAndRegister()-> config().group().register(channel)?:從 boss group 中選擇一個(gè) NioEventLoop 開(kāi)始注冊(cè) serverSocketChannel

          4. EchoServer#b.bind(PORT).sync->AbstractBootStrap#doBind()->initAndRegister()->config().group().register(channel)->AbstractChannel#register0(promise)->AbstractNioChannel#javaChannel().register(eventLoop().unwrappedSelector(), 0, this)?: 將 server socket channel 注冊(cè)到選擇的 NioEventLoop 的 selector

          5. EchoServer#b.bind(PORT).sync()->AbstractBootStrap#doBind()->doBind0()->AbstractChannel#doBind(localAddress)->NioServerSocketChannel#javaChannel().bind(localAddress, config.getBacklog())?: 綁定地址端口開(kāi)始啟動(dòng)

          6. EchoServer#b.bind(PORT).sync()->AbstractBootStrap#doBind()->doBind0()->AbstractChannel#pipeline.fireChannelActive()->AbstractNioChannel#selectionKey.interestOps(interestOps|readInterestOp): 注冊(cè) OP_READ 事件

          上述啟動(dòng)流程中,1、2、3 是由我們自己的線(xiàn)程執(zhí)行的,即 mainThread,4、5、6 是由 Boss Thread 執(zhí)行。相應(yīng)時(shí)序圖如下:

          建立連接

          服務(wù)啟動(dòng)后便是建立連接的過(guò)程了,相應(yīng)過(guò)程及源碼類(lèi)如下:

          1. NioEventLoop#run()->processSelectedKey()?NioEventLoop 中的 selector 輪詢(xún)創(chuàng)建連接事件(OP_ACCEPT)

          2. NioEventLoop#run()->processSelectedKey()->AbstractNioMessageChannel#read->NioServerSocketChannel#doReadMessages()->SocketUtil#accept(serverSocketChannel)?創(chuàng)建 socket channel

          3. NioEventLoop#run()->processSelectedKey()->AbstractNioMessageChannel#fireChannelRead->ServerBootstrap#ServerBootstrapAcceptor#channelRead-> childGroup.register(child)?從worker group 中選擇一個(gè) NioEventLoop 開(kāi)始注冊(cè) socket channel

          4. NioEventLoop#run()->processSelectedKey()->AbstractNioMessageChannel#fireChannelRead->ServerBootstrap#ServerBootstrapAcceptor#channelRead-> childGroup.register(child)->AbstractChannel#register0(promise)-> AbstractNioChannel#javaChannel().register(eventLoop().unwrappedSelector(), 0, this)?將 socket channel 注冊(cè)到選擇的 NioEventLoop 的 selector

          5. NioEventLoop#run()->processSelectedKey()->AbstractNioMessageChannel#fireChannelRead->ServerBootstrap#ServerBootstrapAcceptor#channelRead-> childGroup.register(child)->AbstractChannel#pipeline.fireChannelActive()-> AbstractNioChannel#selectionKey.interestOps(interestOps | readInterestOp)?注冊(cè) OP_ACCEPT 事件

          同樣,上述流程中 1、2、3 的執(zhí)行仍由 Boss Thread 執(zhí)行,直到 4、5 由具體的 Work Thread 執(zhí)行。

          讀寫(xiě)與業(yè)務(wù)處理

          連接建立完畢后是具體的讀寫(xiě),以及業(yè)務(wù)處理邏輯。以 EchoServerHandler 為例,讀取數(shù)據(jù)后會(huì)將數(shù)據(jù)傳播出去供業(yè)務(wù)邏輯處理,此時(shí)的 EchoServerHandler 代表我們的業(yè)務(wù)邏輯,而它的實(shí)現(xiàn)也非常簡(jiǎn)單,就是直接將數(shù)據(jù)寫(xiě)回去。我們將這塊看成一個(gè)整條,流程如下:

          1. NioEventLoop#run()->processSelectedKey() NioEventLoop 中的 selector?輪詢(xún)創(chuàng)建讀取事件(OP_READ)

          2. NioEventLoop#run()->processSelectedKey()->AbstractNioByteChannel#read()nioSocketChannel 開(kāi)始讀取數(shù)據(jù)

          3. NioEventLoop#run()->processSelectedKey()->AbstractNioByteChannel#read()->pipeline.fireChannelRead(byteBuf)把讀取到的數(shù)據(jù)傳播出去供業(yè)務(wù)處理

          4. AbstractNioByteChannel#pipeline.fireChannelRead->EchoServerHandler#channelRead在這個(gè)例子中即 EchoServerHandler 的執(zhí)行

          5. EchoServerHandler#write->ChannelOutboundBuffer#addMessage?調(diào)用 write 方法

          6. EchoServerHandler#flush->ChannelOutboundBuffer#addFlush?調(diào)用 flush 準(zhǔn)備數(shù)據(jù)

          7. EchoServerHandler#flush->NioSocketChannel#doWrite?調(diào)用 flush 發(fā)送數(shù)據(jù)

          在這個(gè)過(guò)程中讀寫(xiě)數(shù)據(jù)都是由 Work Thread 執(zhí)行的,但是業(yè)務(wù)處理可以由我們自定義的線(xiàn)程池來(lái)處理,并且一般我們也是這么做的,默認(rèn)沒(méi)有指定線(xiàn)程的情況下仍然由 Work Thread 代為處理。

          關(guān)閉連接

          服務(wù)處理完畢后,單個(gè)連接的關(guān)閉是什么樣的呢?

          1. NioEventLoop#run()->processSelectedKey()?NioEventLoop 中的 selector 輪詢(xún)創(chuàng)建讀取事件(OP_READ),這里關(guān)閉連接仍然是讀取事件

          2. NioEventLoop#run()->processSelectedKey()->AbstractNioByteChannel#read()->closeOnRead(pipeline)當(dāng)字節(jié)<0 時(shí)開(kāi)始執(zhí)行關(guān)閉 nioSocketChannel

          3. NioEventLoop#run()->processSelectedKey()->AbstractNioByteChannel#read()->closeOnRead(pipeline)->AbstractChannel#close->AbstractNioChannel#doClose()?關(guān)閉 socketChannel

          4. NioEventLoop#run()->processSelectedKey()->AbstractNioByteChannel#read()->closeOnRead(pipeline)->AbstractChannel#close->outboundBuffer.failFlushed/close?清理消息:不接受新信息,fail 掉所有 queue 中消息

          5. NioEventLoop#run()->processSelectedKey()->AbstractNioByteChannel#read()->closeOnRead(pipeline)->AbstractChannel#close->fireChannelInactiveAndDeregister->AbstractNioChannel#doDeregister eventLoop().cancel(selectionKey())?關(guān)閉多路復(fù)用器的 key

          時(shí)序圖如下:

          關(guān)閉服務(wù)

          最后是關(guān)閉整個(gè) Netty 服務(wù):

          1. NioEventLoop#run->closeAll()->selectionKey.cancel/channel.close?關(guān)閉 channel,取消 selectionKey

          2. NioEventLoop#run->confirmShutdown->cancelScheduledTasks?取消定時(shí)任務(wù)

          3. NioEventLoop#cleanup->selector.close()?關(guān)閉 selector

          時(shí)序圖如下,為了好畫(huà)將 NioEventLoop 拆成了 2 塊:

          至此,整個(gè) Netty 的服務(wù)流程就結(jié)束了。



          往期精彩推薦



          騰訊、阿里、滴滴后臺(tái)面試題匯總總結(jié) — (含答案)

          面試:史上最全多線(xiàn)程面試題 !

          最新阿里內(nèi)推Java后端面試題

          JVM難學(xué)?那是因?yàn)槟銢](méi)認(rèn)真看完這篇文章


          END


          關(guān)注作者微信公眾號(hào) —《JAVA爛豬皮》


          了解更多java后端架構(gòu)知識(shí)以及最新面試寶典


          你點(diǎn)的每個(gè)好看,我都認(rèn)真當(dāng)成了


          看完本文記得給作者點(diǎn)贊+在看哦~~~大家的支持,是作者源源不斷出文的動(dòng)力


          作者:fredalxin
          地址:https://fredal.xin/netty-process

          瀏覽 29
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕无码日韩专区免费 | 欧美极品三级 | 激情五月婷婷丁香 | 亚洲婷色五月 | 成人三级视频在线 |