《Netty實戰》 (一) ———————Netty 初探

《Netty實戰》 (一) ———————Netty 初探

在深入Netty 之前我們先從BIO 到 NIO的演變入手

	ServerSocket serverSocket = new ServerSocket(54132);
Socket socket = serverSocket.accept();
//TODO  

上述程式碼 是我們最開始接觸網路程式設計中BIO程式碼。這段程式碼將只能同時處理一個連線,要管理多個併發客戶端,需要為每個新的客戶端socket建立一個新的執行緒。形成如下的格局:

但是會有如下問題: 1、在任何時候都可能有大量的執行緒處於休眠狀態,只能等待輸入或輸出資料。簡單來說就是,因為等待I/O而浪費了整個執行緒資源。

2、需要為每個執行緒的呼叫棧分配記憶體,其預設值的大小區間為64KB到1MB。

3、執行緒的上下文切換帶來不小的開銷。

針對BIO所出現的弊端,非阻塞設計的NIO也應運而生。下面是NIO設計;

selector 是java的非阻塞I/O實現的關鍵。他使用了事件通知API以確定在一組非阻塞套接字中有哪些已經就緒能夠進行I/O相關操作,一個單一執行緒便可以處理多個併發連結。要知道在不是多核的電腦上執行的多執行緒效率並非必單執行緒阻塞佔便宜,因為執行緒的切換也是需要一定的開銷。

在高負載下可靠和高效的處理和排程I/O操作是一項繁瑣而且容易出錯的任務,因而高效能的網路程式設計專家 Netty 便登場了。

Netty 的特性總結

分類Netty 的特性
設計

統一的API,支援多種傳輸型別,阻塞和非阻塞的。

簡單而強大的執行緒模型

真正的無連線資料包套接字支援

連結邏輯元件以支援複用

效能

擁有比java的核心API更高的吞吐量以及更低的延遲

得益於池化和複用,擁有更低的資源消耗

最少的記憶體複製

健壯性

不會因為慢速、快速或者超載而導致OutOfMemoryErro

消除在高速網路中NIO應用程式常見的不公平讀/寫比率

安全性完整的SSL/TLS以及StartTLS支援

Netty 核心元件概述

更多細節內容將會在後續博文展開,這裡只進行概述,方便理解後續的程式碼。

  • Channel,表示一個連線,可以理解為每一個請求,就是一個Channel。
  • ChannelHandler,核心處理業務就在這裡,用於處理業務請求。
  • 回撥:一個回撥其實就是一個方法,一個指向已經被提供給另一個方法的方法引用。這使得後者可以再適當的時候呼叫前者。可能不好理解,下面通過一段程式碼來具體說明。
//當一個新連線已經被建立時,channelActive方法將會被呼叫
public class ConnectHandle extends ChannelInboundHandlerAdapter {
@Override
public void channelActive (ChannelHandlerContext ctx) {
// TODO
}
}
  • Future 提供了另一種在操作完成時通知應用程式的方式。這個物件可以看做是一個非同步操作的結果佔位符;他將在未來的某個時刻完成,並提供對其結果的訪問。JDK所提供的Future只允許手動檢查對應的操作是否已完成,或者一直阻塞直到它完成。因而Netty提供了自己的實現-channelFuture,用於在執行非同步時使用。channelfuture允許我們註冊一個或多個監聽者,然後監聽者的回撥方法會在對應的操作完成後被呼叫。下面通過一個例子來具體說明。
		Channel channel;
//非同步連結遠端節點
ChannelFuture future = channel.connect(new InetSocketAddress("localhost", 54132));
//註冊一個監聽者以便在操作完成時獲得通知
future.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) {
//檢查狀態
if(future.isSuccess()) {
//TODO
}else {
//TODO
}
}
})
  • ChannelHandlerContext,用於傳輸業務資料。
  • ChannelPipeline,用於儲存處理過程需要用到的ChannelHandler和ChannelHandlerContext。

  • 最後

這裡只是簡單的描述了一下Netty,具體的例項程式碼以及核心元件的深入將在以後展現。