認識Netty

        Netty的特性:

Netty提供異步的、事件驅動的網絡應用程序框架和工具,用以快速開發高性能、高可靠性的網絡服務器和客戶端程序,整體來看其包含了以下內容:

  1. 實現了自有的、豐富的Buffer數據結構,徹底解決java NIO ByteBuffer的問題,滿足開發者的日常需求。
  2. 統一的阻塞和非阻塞的IO協議API
  3. 基於靈活、可擴展的事件驅動模型
  4. 爲快速開發提供了豐富的組件和協議支持

       Netty普通使用一般是通過BootStrap來啓動,BootStrap主要分爲兩類:

       1.面向連接(TCP)的BootStrap(ClientBootStrap和ServerBootstrap),

       2.非面向連接(UDP) 的(ConnectionlessBootstrap)。

      

Netty的應用

        面向連接的Netty服務端客戶端使用,第一步:實例化一個BootStrap,並且通過構造方法指定一個ChannelFactory實現,第二步:向bootstrap實例註冊一個自己實現的ChannelPipelineFactory,第三步:如果是服務器端,bootstrap.bind(new InetSocketAddress(port)),然後等待客戶端來連接,如果是客戶端,bootstrap.connect(new InetSocketAddress(host,port))取得一個future,這個時候Netty會去連接遠程主機,在連接完成後,會發起類型爲 CONNECTED的ChannelStateEvent,並且開始在你自定義的Pipeline裏面流轉,如果你註冊的handler有這個事件的響應方法的話那麼就會調用到這個方法。在此之後就是數據的傳輸了。這些可以通過netty Example去了解。下面是一個Netty的server端例子:

        

public static void bootServer() {
 // More terse code to setup the server
 ServerBootstrap bootstrap = new ServerBootstrap(
   new NioServerSocketChannelFactory(
     Executors.newCachedThreadPool(),
     Executors.newCachedThreadPool()));
 
 // Set up the pipeline factory.
 bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
  public ChannelPipeline getPipeline() throws Exception {
   return Channels.pipeline(
    new ObjectDecoder(ClassResolvers.cacheDisabled(getClass().getClassLoader())),
    new DateHandler()
   );
  };
 });
 
 // Bind and start to accept incoming connections.
 bootstrap.bind(new InetSocketAddress("0.0.0.0", 8080));
 slog("Listening on 8080");
}
 
static class DateHandler extends SimpleChannelHandler {
 public void messageReceived(ChannelHandlerContext ctx,MessageEvent e) throws Exception {
  Date date = (Date)e.getMessage();
  // Here's the REALLY important business service at the end of the pipeline
  slog("Hey Guys !  I got a date ! [" + date + "]");
  // Huh ?
  super.messageReceived(ctx, e);
 }  
}

        Netty整體架構很清晰的分成2個部分,ChannelFactory 和ChannelPipelineFactory,前者主要生產網絡通信相關的Channel實例和ChannelSink實例,Netty提供的 ChannelFactory實現基本能夠滿足絕大部分用戶的需求,當然你也可以定製自己的ChannelFactory,後者主要關注於具體傳輸數據的處理,同時也包括其他方面的內容,比如異常處理等等,只要是你希望的,你都可以往裏添加相應的handler,一般 ChannelPipelineFactory由用戶自己實現,因爲傳輸數據的處理及其他操作和業務關聯比較緊密,需要自定義處理的handler。

       

Netty提供了NIO與BIO(OIO)兩種模式處理這些邏輯,其中NIO主要通過一個BOSS線程處理等待鏈接的接入,若干個WORKER線程(從worker線程池中挑選一個賦給Channel實例,因爲Channel實例持有真正的 java網絡對象)接過BOSS線程遞交過來的CHANNEL進行數據讀寫並且觸發相應事件傳遞給pipeline進行數據處理,而BIO(OIO)方式服務器端雖然還是通過一個BOSS線程來處理等待鏈接的接入,但是客戶端是由主線程直接connect,另外寫數據C/S兩端都是直接主線程寫,而數據讀操作是通過一個WORKER 線程BLOCK方式讀取(一直等待,直到讀到數據,除非channel關閉)。

網絡動作歸結到最簡單就是服務器端bind->accept->read->write,客戶端 connect->read->write,一般bind或者connect後會有多次read、write。這種特性導致,bind,accept與read,write的線程分離,connect與read、write線程分離,這樣做的好處就是無論是服務器端還是客戶端吞吐量將有效增大,以便充分利用機器的處理能力,而不是卡在網絡連接上,不過一旦機器處理能力充分利用後,這種方式反而可能會因爲過於頻繁的線程切換導致性能損失而得不償失,並且這種處理模型複雜度比較高。

採用什麼樣的網絡事件響應處理機制對於網絡吞吐量是非常重要的,Netty採用的是標準的SEDA(Staged Event-Driven Architecture)架構[http://en.wikipedia.org/wiki/ Staged_event-driven_architecture],其所設計的事件類型,代表了網絡交互的各個階段,並且在每個階段發生時,觸發相應事件交給初始化時生成的pipeline實例進行處理。事件處理都是通過Channels類的靜態方法調用開始的,將事件、channel傳遞給 channel持有的Pipeline進行處理,Channels類幾乎所有方法都爲靜態,提供一種Proxy的效果(整個工程裏無論何時何地都可以調用其靜態方法觸發固定的事件流轉,但其本身並不關注具體的處理流程)。

Channels部分事件流轉靜態方法
1.fireChannelOpen 2.fireChannelBound 3.fireChannelConnected 4.fireMessageReceived 5.fireWriteComplete 6.fireChannelInterestChanged
7.fireChannelDisconnected 8.fireChannelUnbound 9.fireChannelClosed 10.fireExceptionCaught 11.fireChildChannelStateChanged

Netty提供了全面而又豐富的網絡事件類型,其將java中的網絡事件分爲了兩種類型Upstream和Downstream。一般來說,Upstream類型的事件主要是由網絡底層反饋給Netty的,比如messageReceived,channelConnected等事件,而Downstream類型的事件是由框架自己發起的,比如bind,write,connect,close等事件。





發佈了24 篇原創文章 · 獲贊 14 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章