netty學習之三 channel和channelHandler

netty中負責傳輸的核心是channel接口,它用於全部出站的操做。Channel接口的類層次結構以下 [輸入圖片說明git

  • 每一個Channel都會分配一個ChannelPipeline和ChannelConfig。ChannelConfig負責設置並存儲配置,並容許在運行期間更新它們。傳輸通常有特定的配置設置,只做用於傳輸,沒有其餘的實現。ChannelPipeline容納了使用的ChannelHandler實例,這些ChannelHandler將處理通道傳遞的「入站」和「出站」數據。
    ChannelHandler的實現容許你改變數據狀態和傳輸數據,channelHandler到底能作哪些事情呢?
  1. • 傳輸數據時,將數據從一種格式轉換到另外一種格式
  2. • 異常通知
  3. • Channel變爲有效或無效時得到通知
  4. • Channel被註冊或從EventLoop中註銷時得到通知
  5. • 通知用戶特定事件
  • 這些ChannelHandler實例添加到ChannelPipeline中,在ChannelPipeline中按順序逐個執行。它相似於一個鏈條,有使用過Servlet的讀者可能會更容易理解。
      ChannelPipeline實現了攔截過濾器模式,這意味着咱們鏈接不一樣的ChannelHandler來攔截並處理通過ChannelPipeline的數據或事件。能夠把ChannelPipeline想象成UNIX管道,它容許不一樣的命令鏈(ChannelHandler至關於命令)。你還能夠在運行時根據須要添加ChannelHandler實例到ChannelPipeline或從ChannelPipeline中刪除,這能幫助咱們構建高度靈活的Netty程序。此外,訪問指定的ChannelPipeline和ChannelConfig,你能在Channel自身上進行操做。Channel提供了不少方法,以下列表:
  1. • eventLoop(),返回分配給Channel的EventLoop
  2. • pipeline(),返回分配給Channel的ChannelPipeline
  3. • isActive(),返回Channel是否激活,已激活說明與遠程鏈接對等
  4. • localAddress(),返回已綁定的本地SocketAddress
  5. • remoteAddress(),返回已綁定的遠程SocketAddress
  6. • write(),寫數據到遠程客戶端,數據經過ChannelPipeline傳輸過去
  • 寫數據到遠程已鏈接客戶端能夠調用Channel.write()方法,以下代碼:
Channel channel = ...  
ByteBuf buf = Unpooled.copiedBuffer("your data", CharsetUtil.UTF_8);  
ChannelFuture cf = channel.write(buf);  
cf.addListener(new ChannelFutureListener() {  
     @Override  
     public void operationComplete(ChannelFuture future) {  
	        //Write operation completes without error  
	        if (future.isSuccess()) {  
	            System.out.println(.Write successful.);  
	        } else {  
	            //Write operation completed but because of error  
	            System.err.println(.Write error.);  
	            future.cause().printStacktrace();  
	        }  
	    }  
});
  • Channel是線程安全(thread-safe)的,它能夠被多個不一樣的線程安全的操做,在多線程環境下,全部的方法都是安全的。
  • 下面看下channelHandler和數據如何處理,Handlers自身依賴於ChannelPipeline來決定它們執行的順序,所以不可能經過ChannelPipeline定義處理程序的某些方面,反過來不可能定義也不可能經過ChannelHandler定義ChannelPipeline的某些方面,Netty的ChannelHandler是你的應用程序中處理最多的。即便你沒有意思到這一點,若果你使用Netty應用將至少有一個ChannelHandler參與,換句話說,ChannelHandler對不少事情是關鍵的。那麼ChannelHandler到底是什麼?給ChannelHandler一個定義不容易,咱們能夠理解爲ChannelHandler是一段執行業務邏輯處理數據的代碼,它們來來每每的經過ChannelPipeline。實際上,ChannelHandler是定義一個handler的父接口,ChannelInboundHandler和ChannelOutboundHandler都實現ChannelHandler接口,以下圖:

輸入圖片說明

Netty中有兩個方向的數據流,上圖顯示的入站(ChannelInboundHandler)和出站(ChannelOutboundHandler)之間有一個明顯的區別:若數據是從用戶應用程序到遠程主機則是「出站(outbound)」,相反若數據時從遠程主機到用戶應用程序則是「入站(inbound)」。 爲了使數據從一端到達另外一端,一個或多個ChannelHandler將以某種方式操做數據。這些ChannelHandler會在程序的「引導」階段被添加ChannelPipeline中,而且被添加的順序將決定處理數據的順序。ChannelPipeline的做用咱們能夠理解爲用來管理ChannelHandler的一個容器,每一個ChannelHandler處理各自的數據(例如入站數據只能由ChannelInboundHandler處理),處理完成後將轉換的數據放到ChannelPipeline中交給下一個ChannelHandler繼續處理,直到最後一個ChannelHandler處理完成。 下圖顯示了ChannelPipeline的處理過程:github

輸入圖片說明

  • 上圖顯示ChannelInboundHandler和ChannelOutboundHandler都要通過相同的ChannelPipeline。
  • 在ChannelPipeline中,若是消息被讀取或有任何其餘的入站事件,消息將從ChannelPipeline的頭部開始傳遞給第一個ChannelInboundHandler,這個ChannelInboundHandler能夠處理該消息或將消息傳遞到下一個ChannelInboundHandler中,一旦在ChannelPipeline中沒有剩餘的ChannelInboundHandler後,ChannelPipeline就知道消息已被全部的餓Handler處理完成了。
  • 反過來也是如此,任何出站事件或寫入將從ChannelPipeline的尾部開始,並傳遞到最後一個ChannelOutboundHandler。ChannelOutboundHandler的做用和ChannelInboundHandler相同,它能夠傳遞事件消息到下一個Handler或者本身處理消息。不一樣的是ChannelOutboundHandler是從ChannelPipeline的尾部開始,而ChannelInboundHandler是從ChannelPipeline的頭部開始,當處理完第一個ChannelOutboundHandler處理完成後會出發一些操做,好比一個寫操做。
  • 一個事件能傳遞到下一個ChannelInboundHandler或上一個ChannelOutboundHandler,在ChannelPipeline中經過使用ChannelHandlerContext調用每個方法。Netty提供了抽象的事件基類稱爲ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter。每一個都提供了在ChannelPipeline中經過調用相應的方法將事件傳遞給下一個Handler的方法的實現。咱們能覆蓋的方法就是咱們須要作的處理。

** Netty中發送消息有兩種方法:直接寫入通道或寫入ChannelHandlerContext對象。這兩種方法的主要區別以下:**安全

  • • 直接寫入通道致使處理消息從ChannelPipeline的尾部開始
  • • 寫入ChannelHandlerContext對象致使處理消息從ChannelPipeline的下一個handler開始

完整代碼連接:https://github.com/winstonelei/Smt多線程

相關文章
相關標籤/搜索