摘要:隨著狀態(tài)發(fā)生變化,相應(yīng)的產(chǎn)生。這些被轉(zhuǎn)發(fā)到中的來采取相應(yīng)的操作。當(dāng)收到數(shù)據(jù)或相關(guān)的狀態(tài)改變時,這些方法被調(diào)用,這些方法和的生命周期密切相關(guān)。主要由一系列組成的。采用的線程模型,在同一個線程的中處理所有發(fā)生的事。
「博客搬家」 原地址: 簡書 原發(fā)表時間: 2017-05-05
學(xué)習(xí)了一段時間的 Netty,將重點與學(xué)習(xí)心得總結(jié)如下,本文主要總結(jié)ChannelHandler 及 EventLoop 的知識點和基本用法,本文章節(jié)排序參照《Netty in Action》的章節(jié)排序。
以下內(nèi)容主要參考「并發(fā)編程網(wǎng)」的 《Netty in Action》中文版 以及《Netty in Action》原版圖書,輔助參考 Essential Netty in Action 《Netty 實戰(zhàn)(精髓)》 以及 Netty 官網(wǎng)的 Netty 4.1 JavaDoc 。6. ChannelHandler 和 ChannelPipeline
一個 Channel 正常的生命周期如下圖所示。隨著狀態(tài)發(fā)生變化,相應(yīng)的 event 產(chǎn)生。這些 event 被轉(zhuǎn)發(fā)到 ChannelPipeline 中的 ChannelHandler 來采取相應(yīng)的操作。
6.1 ChannelHandlerChannelHandler 有兩個重要的子接口:
「ChannelInboundHandler」處理輸入數(shù)據(jù)和所有類型的狀態(tài)變化
「ChannelOutboundHandler」處理輸出數(shù)據(jù),可以攔截所有操作
6.1.1 ChannelInboundHandler下表列出接口 ChannelInboundHandler 的方法。當(dāng)收到數(shù)據(jù)或相關(guān) Channel 的狀態(tài)改變時,這些方法被調(diào)用,這些方法和Channel的生命周期密切相關(guān)。
方法 | 描述 |
---|---|
channelRegistered | 當(dāng)一個Channel注冊到EventLoop上,可以處理I/O時被調(diào)用 |
channelUnregistered | 當(dāng)一個Channel從它的EventLoop上解除注冊,不再處理I/O時被調(diào)用 |
channelActive | 當(dāng)Channel變成活躍狀態(tài)時被調(diào)用;Channel是連接/綁定、就緒的 |
channelInactive | 當(dāng)Channel離開活躍狀態(tài),不再連接到某個遠(yuǎn)端時被調(diào)用 |
channelReadComplete | 當(dāng)Channel上的某個讀操作完成時被調(diào)用 |
channelRead | 當(dāng)從Channel中讀數(shù)據(jù)時被調(diào)用 |
輸出的操作和數(shù)據(jù)由 ChannelOutBoundHandler 處理。它的方法可以被 Channel,ChannelPipeline 和 ChannelHandlerContext 調(diào)用,子接口 ChannelOutboundHandler 的主要方法如下:
方法 | 描述 |
---|---|
bind(ChannelHandlerContext,SocketAddress,ChannelPromise) | 請求綁定 Channel 到一個本地地址 |
connect(ChannelHandlerContext, SocketAddress,SocketAddress,ChannelPromise) | 請求連接 Channel 到遠(yuǎn)端 |
disconnect(ChannelHandlerContext, ChannelPromise) | 請求從遠(yuǎn)端斷開 Channel |
close(ChannelHandlerContext,ChannelPromise) | 請求關(guān)閉 Channel |
deregister(ChannelHandlerContext, ChannelPromise) | 請求 Channel 從它的 EventLoop 上解除注冊 |
read(ChannelHandlerContext) | 請求從 Channel 中讀更多的數(shù)據(jù) |
flush(ChannelHandlerContext) | 請求通過 Channel 刷隊列數(shù)據(jù)到遠(yuǎn)端 |
write(ChannelHandlerContext,Object, ChannelPromise) | 請求通過 Channel 寫數(shù)據(jù)到遠(yuǎn)端 |
ChannelInboundHandlerAdapter 和 ChannelOutboundHandlerAdapter 這兩個適配器類分別提供了 ChannelInboundHandler 和 ChannelOutboundHandler 的基本實現(xiàn),它們繼承了共同的父接口 ChannelHandler 的方法,擴(kuò)展了抽象類 ChannelHandlerAdapter。
ChannelHandlerAdapter 提供了工具方法 isSharable()。如果類實現(xiàn)帶 @Sharable 注解,那么這個方法就會返回 true,意味著這個對象可以被添加到多個 ChannelPipeline 中。
ChannelInboundHandlerAdapter 和 ChannelOutboundHandlerAdapter 中的方法調(diào)用相關(guān) ChannelHandlerContext 中的等效方法,因此將事件轉(zhuǎn)發(fā)到管道中的下一個ChannelHandler。
6.1.4 ChannelFuture 和 ChannelPromiseChannelPromise 是 ChannelFuture 的子接口
而 ChannelFuture 是不可變對象
ChannelPromise 定義了可寫的方法,比如 setSuccess(), setFailure()
6.1.5 釋放資源1. 輸入方向「Inbound」
當(dāng)一個 ChannelInboundHandler 實現(xiàn)類重寫 channelRead() 方法時,它要負(fù)責(zé)釋放 ByteBuf 相關(guān)的內(nèi)存??墒褂?Netty 提供的工具方法:
ReferenceCountUtil.release(「ByteBuf 的對象」)
更簡單的,可使用子類 SimpleChannelInboundHandler ,一條消息在被 ChannelRead0() 讀取后,會被自動釋放資源,此時任何對消息的引用都會變成無效,所以不能保存這些引用待后來使用。
2. 輸出方向「Outbound」
在輸出方向,如果處理一個 write() 操作并且丟棄一條消息(沒有寫入 Channel),就應(yīng)該負(fù)責(zé)釋放這條消息。
@ChannelHandler.Sharable public class DiscardOutboundHandler extends ChannelOutboundHandlerAdapter { @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { ReferenceCountUtil.release(msg); //使用 ReferenceCountUtil.release(...) 釋放資源 promise.setSuccess(); //通知 ChannelPromise 數(shù)據(jù)已經(jīng)被處理 }
如果一個消息被“消費”或者丟棄,沒有送到 ChannelPipeline 中的下一個 ChannelOutboundHandler,用戶就要負(fù)責(zé)調(diào)用 ReferenceCountUtil.release()。如果消息到達(dá)了真正的傳輸層,在它被寫到 Socket 中或者 Channel 關(guān)閉時,會被自動釋放,用戶不用管。
6.2 ChannelPipeline 接口每個新創(chuàng)建的 Channel 都會分配一個新的 ChannelPipeline,Channel 不可以更換或解除當(dāng)前的 ChannelPipeline,在 Netty 組件的整個生命周期中這個關(guān)系是固定的。
一個 ChannelPipeline 可看成是一串 ChannelHandler 實例,攔截穿過 Channel 的輸入輸出 event。
根據(jù)來源,一個 event 可以被一個 ChannelInboundHandler 或 ChannelOutboundHandler 處理。接下來,通過調(diào)用 ChannelHandlerContext 的方法,event 會被轉(zhuǎn)發(fā)到下一個同類型的 handler。
6.2.1 ChannelHandlerContext通過 ChannelHandlerContext,一個 handler 可以通知 ChannelPipeline 中的下一個ChannelHandler,甚至動態(tài)改動下一個ChannelHandler 所屬的 ChannelPipeline。
ChannelPipeline 主要由一系列 ChannelHandler 組成的。ChannelPipeline 提供在 ChannelPipeline 中傳送 event 的方法。
ChannelHandlerContext 的一些方法和其他類(Channel 和 ChannelPipeline)的方法名字相似,但是 ChannelHandlerContext 的方法采用了更短的 event 傳遞路程。我們應(yīng)該盡可能利用這一點來實現(xiàn)最好的性能。
如果你在 Channel 或者 ChannelPipeline 實例上調(diào)用這些方法,它們的調(diào)用會穿過整個 pipeline。而在 ChannelHandlerContext 上調(diào)用的同樣的方法,僅僅從當(dāng)前 ChannelHandler 開始,走到 pipeline 中下一個可以處理這個 event 的 ChannelHandler。
「本節(jié)參考」 第六章 ChannelHandler 和 ChannelPipeline
7. EventLoop 和 EventLoopGroup 7.1 Java 基本的線程池模式從池中空閑的線程中選出一個,分配一個提交的task「一個Runnable的實現(xiàn)」
當(dāng)task完成,線程返回池中,等待復(fù)用「下一次task分配」
7.2 EventLoop「事件循環(huán)」EventLoop 始終由一個線程驅(qū)動
一個 EventLoop 可以被指派來服務(wù)多個 Channel
一個 Channel 只擁有一個 EventLoop
task (Runnable或Callable) 可以直接提交到 EventLoop 實現(xiàn)即刻或者延后執(zhí)行。根據(jù)配置和可用的CPU核,可以創(chuàng)建多個 EventLoop 來優(yōu)化資源利用。
一個 event 的本質(zhì)決定了它將如何被處理;它可能從網(wǎng)絡(luò)協(xié)議棧傳送數(shù)據(jù)到你的應(yīng)用,或者反過來,或者做一些完全不一樣的事情。但是 event 處理邏輯必須足夠通用和靈活,來對付所有可能的情況。
所以,在 Netty 4,所有的 I/O 操作和 event 都是由分配給 EventLoop 的那一個 Thread 來處理的。Netty 4 采用的線程模型,在同一個線程的 EventLoop 中處理所有發(fā)生的事。
7.3 EventLoopGroupEventLoopGroup 負(fù)責(zé)分配 EventLoop 到新創(chuàng)建的 Channel
異步實現(xiàn)只用了很少 EventLoop,這幾個 EventLoop 被所有 Channel 共享
一但 Channel 被指派了一個 EventLoop,在它的整個生命周期過程中,都會用這個 EventLoop
為 Channel 的 I/O 和 event 提供服務(wù)的 EventLoop 都包含在一個 EventLoopGroup 中。EventLoop 創(chuàng)建和分配的方式根據(jù)傳輸實現(xiàn)的不同而有所不同。
異步實現(xiàn)只用了很少幾個 EventLoop(和它們關(guān)聯(lián)的線程),在目前 Netty 的模型中,這幾個 EventLoop 被所有 Channel 共享。這讓很多 Channel 被最少數(shù)量的線程服務(wù),而不是每個 Channel 分配一個線程。
EventLoopGroup 負(fù)責(zé)分配一個 EventLoop 到每個新創(chuàng)建的 Channel。在目前的實現(xiàn)中,采用循環(huán) (round-robin) 策略可以滿足一個平衡的分配,同一個 Eventloop 還可能會被分配到多個 Channel。
「本節(jié)參考」 第七章 EventLoop和線程模型
參考鏈接《Netty in Action》中文版
Essential Netty in Action 《Netty 實戰(zhàn)(精髓)》
Netty 4.1 JavaDoc
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/68250.html
摘要:它使用了事件通知以確定在一組非阻塞套接字中有哪些已經(jīng)就緒能夠進(jìn)行相關(guān)的操作。目前,可以把看作是傳入入站或者傳出出站數(shù)據(jù)的載體。出站事件是未來將會觸發(fā)的某個動作的操作結(jié)果,這些動作包括打開或者關(guān)閉到遠(yuǎn)程節(jié)點的連接將數(shù)據(jù)寫到或者沖刷到套接字。 netty的概念 定義 Netty 是一款異步的事件驅(qū)動的網(wǎng)絡(luò)應(yīng)用程序框架,支持快速地開發(fā)可維護(hù)的高性能的面向協(xié)議的服務(wù)器和客戶端。我們可以很簡單的...
摘要:可以用來接收入站事件和數(shù)據(jù),隨后使用應(yīng)用程序的業(yè)務(wù)邏輯進(jìn)行處理。因為用戶并不是關(guān)心所有的事件,因此提供了抽象類和。抽象類最常見的一個情況,你的應(yīng)用程序會利用一個來接受解碼消息,并對該數(shù)據(jù)應(yīng)用業(yè)務(wù)邏輯。 Channel、EventLoop和ChannelFuture Channel——Socket; EventLoop——控制流、多線程處理、并發(fā) ChannelFuture異步通知 ...
摘要:支持很多協(xié)議,并且提供用于數(shù)據(jù)處理的容器。我們已經(jīng)知道由特定事件觸發(fā)。可專用于幾乎所有的動作,包括將一個對象轉(zhuǎn)為字節(jié)或相反,執(zhí)行過程中拋出的異常處理。提供了一個容器給鏈并提供了一個用于管理沿著鏈入站和出站事件的流動。子類通過進(jìn)行注冊。 前兩天寫了一點netty相關(guān)的知識,并寫了一個demo,但是對其原理還是沒有深入,今天我們來做一次研究吧 首先讓我們來認(rèn)識一下netty的幾個核心人物吧...
摘要:在上一篇源碼實戰(zhàn)系列三全剖析中,我們詳細(xì)分析了的初始化過程,并得出了如下結(jié)論在中,每一個都有一個對象,并且其內(nèi)部本質(zhì)上就是一個雙向鏈表本篇我們將深入源碼內(nèi)部,對其一探究竟,給大家一個全方位解析。 在上一篇《Netty4.x 源碼實戰(zhàn)系列(三):NioServerSocketChannel全剖析》中,我們詳細(xì)分析了NioServerSocketChannel的初始化過程,并得出了如下結(jié)論...
摘要:概念與概念一致用以連接設(shè)備文件等的紐帶例如將網(wǎng)絡(luò)的讀寫客戶端發(fā)起連接主動關(guān)閉連接鏈路關(guān)閉獲取通信雙方的網(wǎng)絡(luò)地址等的類型主要有兩種非阻塞以及阻塞數(shù)據(jù)傳輸類型有兩種按事件消息傳遞以及按字節(jié)傳遞適用方類型也有兩種服務(wù)器以及客戶端還有一些根據(jù)傳輸協(xié) ChannelHandler Channel Channel 概念與 java.nio.channel 概念一致, 用以連接IO設(shè)備 (socke...
閱讀 2926·2019-08-30 15:55
閱讀 2919·2019-08-30 15:53
閱讀 2366·2019-08-26 13:47
閱讀 2646·2019-08-26 13:43
閱讀 3234·2019-08-26 13:33
閱讀 2875·2019-08-26 11:53
閱讀 1852·2019-08-23 18:35
閱讀 878·2019-08-23 17:16