<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 的整體流程,還有誰不會?

          共 5116字,需瀏覽 11分鐘

           ·

          2021-05-05 08:48

          點擊關注公眾號,Java干貨及時送達

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

          本文基于版本 4.1.46,同時只描述類而不展示具體源碼。

          Netty 的整體流程

          Netty 的整體流程相對來說還是比較復雜的,初學者往往會被繞暈。

          所以這里總結了一下整體的流程,從而對 Netty 的整體服務流程有一個大致的了解。從功能上,流程可以分為服務啟動、建立連接、讀取數(shù)據(jù)、業(yè)務處理、發(fā)送數(shù)據(jù)、關閉連接以及關閉服務。

          整體流程如下所示(圖中沒有包含關閉的部分):

          服務啟動

          服務啟動時,我們以 example 代碼中的 EchoServer 為例,啟動的過程以及相應的源碼類如下:

          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 中選擇一個 NioEventLoop 開始注冊 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 注冊到選擇的 NioEventLoop 的 selector
          5. EchoServer#b.bind(PORT).sync()->AbstractBootStrap#doBind()->doBind0()->AbstractChannel#doBind(localAddress)->NioServerSocketChannel#javaChannel().bind(localAddress, config.getBacklog()) : 綁定地址端口開始啟動
          6. EchoServer#b.bind(PORT).sync()->AbstractBootStrap#doBind()->doBind0()->AbstractChannel#pipeline.fireChannelActive()->AbstractNioChannel#selectionKey.interestOps(interestOps|readInterestOp): 注冊 OP_READ 事件

          上述啟動流程中,1、2、3 是由我們自己的線程執(zhí)行的,即 mainThread,4、5、6 是由 Boss Thread 執(zhí)行。另外,關注公眾號Java技術棧,在后臺回復:面試,可以獲取我整理的 Java 多線程系列面試題和答案,非常齊全。

          相應時序圖如下:

          建立連接

          服務啟動后便是建立連接的過程了,相應過程及源碼類如下:

          1. NioEventLoop#run()->processSelectedKey() NioEventLoop 中的 selector 輪詢創(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 中選擇一個 NioEventLoop 開始注冊 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 注冊到選擇的 NioEventLoop 的 selector
          5. NioEventLoop#run()->processSelectedKey()->AbstractNioMessageChannel#fireChannelRead->ServerBootstrap#ServerBootstrapAcceptor#channelRead-> childGroup.register(child)->AbstractChannel#pipeline.fireChannelActive()-> AbstractNioChannel#selectionKey.interestOps(interestOps | readInterestOp) 注冊 OP_ACCEPT 事件

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

          讀寫與業(yè)務處理

          連接建立完畢后是具體的讀寫,以及業(yè)務處理邏輯。以 EchoServerHandler 為例,讀取數(shù)據(jù)后會將數(shù)據(jù)傳播出去供業(yè)務邏輯處理,此時的 EchoServerHandler 代表我們的業(yè)務邏輯,而它的實現(xiàn)也非常簡單,就是直接將數(shù)據(jù)寫回去。

          我們將這塊看成一個整條,流程如下:

          1. NioEventLoop#run()->processSelectedKey() NioEventLoop 中的 selector 輪詢創(chuàng)建讀取事件(OP_READ)
          2. NioEventLoop#run()->processSelectedKey()->AbstractNioByteChannel#read() nioSocketChannel 開始讀取數(shù)據(jù)
          3. NioEventLoop#run()->processSelectedKey()->AbstractNioByteChannel#read()->pipeline.fireChannelRead(byteBuf)把讀取到的數(shù)據(jù)傳播出去供業(yè)務處理
          4. AbstractNioByteChannel#pipeline.fireChannelRead->EchoServerHandler#channelRead在這個例子中即 EchoServerHandler 的執(zhí)行
          5. EchoServerHandler#write->ChannelOutboundBuffer#addMessage 調用 write 方法
          6. EchoServerHandler#flush->ChannelOutboundBuffer#addFlush 調用 flush 準備數(shù)據(jù)
          7. EchoServerHandler#flush->NioSocketChannel#doWrite 調用 flush 發(fā)送數(shù)據(jù)

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

          關閉連接

          服務處理完畢后,單個連接的關閉是什么樣的呢?

          1. NioEventLoop#run()->processSelectedKey() NioEventLoop 中的 selector 輪詢創(chuàng)建讀取事件(OP_READ),這里關閉連接仍然是讀取事件
          2. NioEventLoop#run()->processSelectedKey()->AbstractNioByteChannel#read()->closeOnRead(pipeline)當字節(jié)<0 時開始執(zhí)行關閉 nioSocketChannel
          3. NioEventLoop#run()->processSelectedKey()->AbstractNioByteChannel#read()->closeOnRead(pipeline)->AbstractChannel#close->AbstractNioChannel#doClose() 關閉 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()) 關閉多路復用器的 key

          時序圖如下:

          關閉服務

          最后是關閉整個 Netty 服務:

          1. NioEventLoop#run->closeAll()->selectionKey.cancel/channel.close 關閉 channel,取消 selectionKey
          2. NioEventLoop#run->confirmShutdown->cancelScheduledTasks 取消定時任務
          3. NioEventLoop#cleanup->selector.close() 關閉 selector

          時序圖如下,為了好畫將 NioEventLoop 拆成了 2 塊:

          至此,整個 Netty 的服務流程就結束了。

          完了,哈哈,還有誰不會嗎??






          關注Java技術棧看更多干貨



          獲取 Spring Boot 實戰(zhàn)筆記!
          瀏覽 32
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  中文人妻无码一区二区三区久久 | 操女明星爽不爽操死你操得爽死你 | 亚洲日韩在线免费观看 | 伊人电影成人网 | 欧美人与禽性XXXXX杂性 欧美日韩一区二区三区,麻豆 |