Netty系列(5) 以一個(gè)例子分析 Netty 源碼

前言

本文 debug 的代碼來(lái)自于
[ http://www.itdecent.cn/p/209576915459 ] 一文中的
[ 2.1 LineBasedFrameDecoder + StringDecoder (基于回車(chē)換行符解決粘包拆包問(wèn)題) ]

1.服務(wù)端的啟動(dòng)

Reactor模式.png

1.1 Server啟動(dòng)流程

1.初始化
1.1 屬性賦值
>> 初始化創(chuàng)建 2 個(gè) NioEventLoopGroup:
其中 boosGroup 用于 Accetpt 連接建立事件并分發(fā)請(qǐng)求,workerGroup 用于處理 I/O 讀寫(xiě)事件和業(yè)務(wù)邏輯。
>> 基于 ServerBootstrap(服務(wù)端啟動(dòng)引導(dǎo)類(lèi)):
配置 EventLoopGroup、Channel 類(lèi)型,連接參數(shù)、配置入站、出站事件 handler。
1.2 初始化

2.register

1.2 Server啟動(dòng)之后

Server 端包含 1 個(gè) Boss NioEventLoopGroup 和 1 個(gè) Worker NioEventLoopGroup。
NioEventLoopGroup 相當(dāng)于 1 個(gè)事件循環(huán)組,這個(gè)組里包含多個(gè)事件循環(huán) NioEventLoop,
每個(gè) NioEventLoop 包含 1 個(gè) Selector 和 1 個(gè)事件循環(huán)線程。

#每個(gè) boss NioEventLoop 循環(huán)執(zhí)行的任務(wù)包含 3 步:
1)輪詢 Accept 事件;
2)處理 Accept I/O 事件,與 Client 建立連接,生成 NioSocketChannel,并將 NioSocketChannel 注冊(cè)到某個(gè) Worker NioEventLoop 的 Selector 上;
3)處理任務(wù)隊(duì)列中的任務(wù),runAllTasks。任務(wù)隊(duì)列中的任務(wù)包括用戶調(diào)用 eventloop.execute 或 schedule 執(zhí)行的任務(wù),或者其他線程提交到該 eventloop 的任務(wù)。

#每個(gè) worker NioEventLoop 循環(huán)執(zhí)行的任務(wù)包含 3 步:
1)輪詢 Read、Write 事件;
2)處理 I/O 事件,即 Read、Write 事件,在 NioSocketChannel 可讀、可寫(xiě)事件發(fā)生時(shí)進(jìn)行處理;
3)處理任務(wù)隊(duì)列中的任務(wù),runAllTasks。

#其中任務(wù)隊(duì)列中的 Task 有 3 種典型使用場(chǎng)景:
1) 用戶程序自定義的普通任務(wù):
ctx.channel().eventLoop().execute(newRunnable() {
   @Override
   publicvoidrun() {
        //...
   }
});
2) 非當(dāng)前 Reactor 線程調(diào)用 Channel 的各種方法:
例如在推送系統(tǒng)的業(yè)務(wù)線程里面,根據(jù)用戶的標(biāo)識(shí),找到對(duì)應(yīng)的 Channel 引用,
然后調(diào)用 Write 類(lèi)方法向該用戶推送消息,就會(huì)進(jìn)入到這種場(chǎng)景。
最終的 Write 會(huì)提交到任務(wù)隊(duì)列中后被異步消費(fèi)。
3) 用戶自定義定時(shí)任務(wù):
ctx.channel().eventLoop().schedule(newRunnable() {
  @Override
  publicvoidrun() {
    ...
  }
}, 60, TimeUnit.SECONDS);

3.數(shù)據(jù)在ChannelPipeline中的具體流動(dòng)過(guò)程

// Channel-ChannelPipeline-ChannelHandlerContext-ChannelHandler

當(dāng)client與server建立tcp連接后, 即在二者之間創(chuàng)建了一個(gè)channel, 
server也會(huì)在該channl上, 創(chuàng)建一條channelpipeline,
并在channlpipeline中添加一系列的channelhandlercontext及channelhandler.
...childHandler(new ChannelInitializer<NioSocketChannel>() {
    @Override
    protected void initChannel(NioSocketChannel ch) throws Exception {
        ch.pipeline()
        // 這里結(jié)合 LineBasedFrameDecoder + StringDecoder 實(shí)現(xiàn)粘包拆包的處理, 其中 LineBasedFrameDecoder 是基于 \n 或 \r\n 實(shí)現(xiàn)
        // 這里需要注意: 單條消息不能超過(guò)給定的最大限度, 否則會(huì)拋出異常
        .addLast("lineBasedFrameDecoder", new LineBasedFrameDecoder(1024))
        .addLast("stringDecoder", new StringDecoder())
        .addLast("serverhandler01", new ServerHandler01());
    }
});
#以fireChannelRead為例
當(dāng)client向server端通過(guò)Channel進(jìn)行數(shù)據(jù)交互時(shí)(連接建立之后), 
請(qǐng)求數(shù)據(jù)在server端的channelpipeline中的流轉(zhuǎn)過(guò)程如下:
step1.png
step2.png
step3.png
step4.png
step5.png
step6.png
step7.png
step8.png
step9.png
請(qǐng)求到達(dá)server后, 在childHandler中的ChannelPipeline中的堆棧信息.png
step9之后, 然后重復(fù) step5-step8, 直到鏈表的尾部.

當(dāng)從server端進(jìn)行出站時(shí), 反過(guò)來(lái), 先從鏈表的尾部開(kāi)始, 尋找outbound對(duì)應(yīng)的handler, 
直至鏈表頭部, 至此, 在服務(wù)端的handler的出入站便結(jié)束了.

客戶端的出入站與之類(lèi)似, 此處不再另行分析.

#這里需要注意的是: 
>> 如果自定義 ChannelInboundHandler 時(shí), 請(qǐng)?jiān)u估是否要在對(duì)應(yīng)方法里調(diào)用firexxx方法, 
以便于將事件繼續(xù)傳遞給ChannelHandlerContext的雙向鏈表中的下一個(gè)節(jié)點(diǎn), 否則, 將可能停止事件傳播, 帶來(lái)問(wèn)題.
>> 同樣的, 如果自定義 ChannelOutboundHandler時(shí), 也請(qǐng)?jiān)u估是否要在對(duì)應(yīng)的方法里, 調(diào)用write或其他方法,
以便于將事件繼續(xù)傳遞給ChannelHandlerContext的雙向鏈表中的下一個(gè)節(jié)點(diǎn), 否則, 將可能停止事件傳播, 帶來(lái)問(wèn)題.

Netty中如何解決select空輪詢導(dǎo)致cpu使用率升至100%的bug
https://blog.csdn.net/qq_41884976/article/details/91913820

參考資料
李林鋒. (2015). Netty權(quán)威指南(第2版).
https://blog.csdn.net/u010739551/article/details/80519295
https://segmentfault.com/a/1190000007282789
https://segmentfault.com/a/1190000007283053

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容