1. 程式人生 > >【死磕Netty】-----Netty的核心元件

【死磕Netty】-----Netty的核心元件

在第一篇部落格中(【死磕Netty】—–NIO基礎詳解),那一大坨的服務端、客戶端程式碼各位應該看著都會害怕。博主在 15 年寫過 NIO,那滋味的酸爽現在都還記憶猶新,而且執行後,中途還會出現異常,所以開發一個具有較好的穩定性和可靠性的 NIO 程式還是挺有難度的。於是 Netty 出現,把我們從水深火熱當中解救出來。

什麼是 Netty?

Netty 是一款提供非同步的、事件驅動的網路應用程式框架和工具,用以快速開發高效能、高可靠性的網路伺服器和客戶端程式

也就是說,Netty 是一個基於 NIO 的客戶、伺服器端程式設計框架,使用 Netty 可以確保你快速和簡單地開發出一個網路應用,例如實現了某種協議的客戶,服務端應用。Netty 相當簡化和流線化了網路應用的程式設計開發過程,例如,TCP 和 UDP 的 socket 服務開發。(以上摘自百度百科)。

Netty具有如下特性(摘自《Netty in Action》)

分類 Netty的特性
設計 統一的API,支援多種傳輸型別,阻塞和非阻塞的
簡單而強大的執行緒模型
真正的無連線資料報套接字支援
連結邏輯元件以支援複用
易於使用 詳實的 Javadoc 和大量的示例集
不需要超過JdK 1.6+的依賴
效能 擁有比 Java 的核心 API 更高的吞吐量以及更低的延遲
得益於池化和複用,擁有更低的資源消耗
最少的記憶體複製
健壯性 不會因為慢速、快速或者超載的連線而導致 OutOfMemoryError
消除在高速網路中 NIO 應用程式常見的不公平讀/寫比率
安全性 完整的 SSL/TLS 以及 StartTLs 支援
可用於受限環境下,如 Applet 和 OSGI
社群驅動 釋出快速而且頻繁

Netty核心元件

為了後期更好地理解和進一步深入 Netty,有必要總體認識一下 Netty 所用到的核心元件以及他們在整個 Netty 架構中是如何協調工作的。Nettty 有如下幾個核心元件:

  • Channel
  • ChannelFuture
  • EventLoop
  • ChannelHandler
  • ChannelPipeline

Channel

Channel 是 Netty 網路操作抽象類,它除了包括基本的 I/O 操作,如 bind、connect、read、write 之外,還包括了 Netty 框架相關的一些功能,如獲取該 Channe l的 EventLoop。

在傳統的網路程式設計中,作為核心類的 Socket ,它對程式設計師來說並不是那麼友好,直接使用其成本還是稍微高了點。而Netty 的 Channel 則提供的一系列的 API ,它大大降低了直接與 Socket 進行操作的複雜性。而相對於原生 NIO 的 Channel,Netty 的 Channel 具有如下優勢(摘自《Netty權威指南(第二版)》):

  • 在 Channel 介面層,採用 Facade 模式進行統一封裝,將網路 I/O 操作、網路 I/O 相關聯的其他操作封裝起來,統一對外提供。
  • Channel 介面的定義儘量大而全,為 SocketChannel 和 ServerSocketChannel 提供統一的檢視,由不同子類實現不同的功能,公共功能在抽象父類中實現,最大程度地實現功能和介面的重用。
  • 具體實現採用聚合而非包含的方式,將相關的功能類聚合在 Channel 中,有 Channel 統一負責和排程,功能實現更加靈活。

EventLoop

Netty 基於事件驅動模型,使用不同的事件來通知我們狀態的改變或者操作狀態的改變。它定義了在整個連線的生命週期裡當有事件發生的時候處理的核心抽象。

Channel 為Netty 網路操作抽象類,EventLoop 主要是為Channel 處理 I/O 操作,兩者配合參與 I/O 操作。

下圖是Channel、EventLoop、Thread、EventLoopGroup之間的關係(摘自《Netty In Action》):

Channel、EventLoop、Thread、EventLoopGroup

  • 一個 EventLoopGroup 包含一個或多個 EventLoop。
  • 一個 EventLoop 在它的生命週期內只能與一個Thread繫結。
  • 所有有 EnventLoop 處理的 I/O 事件都將在它專有的 Thread 上被處理。
  • 一個 Channel 在它的生命週期內只能註冊與一個 EventLoop。
  • 一個 EventLoop 可被分配至一個或多個 Channel 。

當一個連線到達時,Netty 就會註冊一個 Channel,然後從 EventLoopGroup 中分配一個 EventLoop 繫結到這個Channel上,在該Channel的整個生命週期中都是有這個繫結的 EventLoop 來服務的。

ChannelFuture

Netty 為非同步非阻塞,即所有的 I/O 操作都為非同步的,因此,我們不能立刻得知訊息是否已經被處理了。Netty 提供了 ChannelFuture 介面,通過該介面的 addListener() 方法註冊一個 ChannelFutureListener,當操作執行成功或者失敗時,監聽就會自動觸發返回結果。

ChannelHandler

ChannelHandler 為 Netty 中最核心的元件,它充當了所有處理入站和出站資料的應用程式邏輯的容器。ChannelHandler 主要用來處理各種事件,這裡的事件很廣泛,比如可以是連線、資料接收、異常、資料轉換等。

ChannelHandler 有兩個核心子類 ChannelInboundHandler 和 ChannelOutboundHandler,其中 ChannelInboundHandler 用於接收、處理入站資料和事件,而 ChannelOutboundHandler 則相反。

ChannelPipeline

ChannelPipeline 為 ChannelHandler 鏈提供了一個容器並定義了用於沿著鏈傳播入站和出站事件流的 API。一個數據或者事件可能會被多個 Handler 處理,在這個過程中,資料或者事件經流 ChannelPipeline,由 ChannelHandler 處理。在這個處理過程中,一個 ChannelHandler 接收資料後處理完成後交給下一個 ChannelHandler,或者什麼都不做直接交給下一個 ChannelHandler。

這裡寫圖片描述

當一個數據流進入 ChannlePipeline 時,它會從 ChannelPipeline 頭部開始傳給第一個 ChannelInboundHandler ,當第一個處理完後再傳給下一個,一直傳遞到管道的尾部。與之相對應的是,當資料被寫出時,它會從管道的尾部開始,先經過管道尾部的 “最後” 一個ChannelOutboundHandler,當它處理完成後會傳遞給前一個 ChannelOutboundHandler 。

當 ChannelHandler 被新增到 ChannelPipeline 時,它將會被分配一個 ChannelHandlerContext,它代表了 ChannelHandler 和 ChannelPipeline 之間的繫結。其中 ChannelHandler 新增到 ChannelPipeline 過程如下:
1. 一個 ChannelInitializer 的實現被註冊到了 ServerBootStrap中
2. 當 ChannelInitializer.initChannel() 方法被呼叫時,ChannelInitializer 將在 ChannelPipeline 中安裝一組自定義的 ChannelHandler
3. ChannelInitializer 將它自己從 ChannelPipeline 中移除

謝謝閱讀,祝好!!!

參考資料

  • 《Netty In Action》