正如我們前面解釋的,非阻塞 I/O 不迫使我們等待完成的操作。在這種能力的基礎上,真正的異步 I/O 是一個重要的一步:一個異步方法完成時立即返回并直接或稍后通知用戶。
正如我們將看到的,在一個網絡環境的異步模型可以更有效地利用資源,可以在快速連續執行多個調用。
### [](https://github.com/waylau/essential-netty-in-action/blob/master/GETTING%20STARTED/Building%20Blocks.md#channel)Channel
一個?[Channel](http://docs.oracle.com/javase/7/docs/api/java/nio/channels/Channel.html)?是 NIO 基本的結構。它代表了一個開放的連接到一個實體如硬件設備、文件、網絡套接字,或程序組件,能夠執行一個或多個不同的 I/O 操作,例如讀或寫。
現在,把 Channel 想象成一個可以“打開”或“關閉”,“連接”或“斷開”和作為傳入和傳出數據的運輸工具。
### [](https://github.com/waylau/essential-netty-in-action/blob/master/GETTING%20STARTED/Building%20Blocks.md#callback-回調)Callback (回調)
callback (回調)是一個簡單的方法,提供給另一種方法作為引用,這樣后者就可以在某個合適的時間調用前者。這種技術被廣泛使用在各種編程的情況下,最常見的方法之一通知給其他人操作已完成。
Netty 內部使用回調處理事件時。一旦這樣的回調被觸發,事件可以由接口 ChannelHandler 的實現來處理。如下面的代碼,一旦一個新的連接建立了,調用 channelActive(),并將打印一條消息。
Listing 1.2 ChannelHandler triggered by a callback
~~~
public class ConnectHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception { //1
System.out.println(
"Client " + ctx.channel().remoteAddress() + " connected");
}
}
~~~
1.當建立一個新的連接時調用 ChannelActive()
### [](https://github.com/waylau/essential-netty-in-action/blob/master/GETTING%20STARTED/Building%20Blocks.md#future)Future
Future 提供了另外一種通知應用操作已經完成的方式。這個對象作為一個異步操作結果的占位符,它將在將來的某個時候完成并提供結果。
JDK 附帶接口 java.util.concurrent.Future ,但所提供的實現只允許您手動檢查操作是否完成或阻塞了。這是很麻煩的,所以 Netty 提供自己了的實現,ChannelFuture,用于在執行異步操作時使用。
ChannelFuture 提供多個附件方法來允許一個或者多個 ChannelFutureListener 實例。這個回調方法 operationComplete() 會在操作完成時調用。事件監聽者能夠確認這個操作是否成功或者是錯誤。如果是后者,我們可以檢索到產生的 Throwable。簡而言之, ChannelFutureListener 提供的通知機制不需要手動檢查操作是否完成的。
每個 Netty 的 outbound I/O 操作都會返回一個 ChannelFuture;這樣就不會阻塞。這就是 Netty 所謂的“自底向上的異步和事件驅動”。
下面例子簡單的演示了作為 I/O 操作的一部分 ChannelFuture 的返回。當調用 connect() 將會直接是非阻塞的,并且調用在背后完成。由于線程是非阻塞的,所以無需等待操作完成,而可以去干其他事,因此這令資源利用更高效。
Listing 1.3 Callback in action
~~~
Channel channel = ...;
//不會阻塞
ChannelFuture future = channel.connect(
new InetSocketAddress("192.168.0.1", 25));
~~~
1.異步連接到遠程地址
下面代碼描述了如何利用 ChannelFutureListener 。首先,連接到遠程地址。接著,通過 ChannelFuture 調用 connect() 來 注冊一個新ChannelFutureListener。當監聽器被通知連接完成,我們檢查狀態。如果是成功,就寫數據到 Channel,否則我們檢索 ChannelFuture 中的Throwable。
注意,錯誤的處理取決于你的項目。當然,特定的錯誤是需要加以約束 的。例如,在連接失敗的情況下你可以嘗試連接到另一個。
Listing 1.4 Callback in action
~~~
Channel channel = ...;
//不會阻塞
ChannelFuture future = channel.connect( //1
new InetSocketAddress("192.168.0.1", 25));
future.addListener(new ChannelFutureListener() { //2
@Override
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) { //3
ByteBuf buffer = Unpooled.copiedBuffer(
"Hello", Charset.defaultCharset()); //4
ChannelFuture wf = future.channel().writeAndFlush(buffer); //5
// ...
} else {
Throwable cause = future.cause(); //6
cause.printStackTrace();
}
}
});
~~~
1.異步連接到遠程對等。調用立即返回并提供 ChannelFuture。
2.操作完成后通知注冊一個 ChannelFutureListener 。
3.當 operationComplete() 調用時檢查操作的狀態。
4.如果成功就創建一個 ByteBuf 來保存數據。
5.異步發送數據到遠程。再次返回ChannelFuture。
6.如果有一個錯誤則拋出 Throwable,描述錯誤原因。
### [](https://github.com/waylau/essential-netty-in-action/blob/master/GETTING%20STARTED/Building%20Blocks.md#event-和-handler)Event 和 Handler
Netty 使用不同的事件來通知我們更改的狀態或操作的狀態。這使我們能夠根據發生的事件觸發適當的行為。
這些行為可能包括:
* 日志
* 數據轉換
* 流控制
* 應用程序邏輯
由于 Netty 是一個網絡框架,事件很清晰的跟入站或出站數據流相關。因為一些事件可能觸發傳入的數據或狀態的變化包括:
* 活動或非活動連接
* 數據的讀取
* 用戶事件
* 錯誤
出站事件是由于在未來操作將觸發一個動作。這些包括:
* 打開或關閉一個連接到遠程
* 寫或沖刷數據到 socket
每個事件都可以分配給用戶實現處理程序類的方法。這說明了事件驅動的范例可直接轉換為應用程序構建塊。
圖1.3顯示了一個事件可以由一連串的事件處理器來處理
Figure 1.3 Event Flow
[](https://github.com/waylau/essential-netty-in-action/blob/master/images/Figure%201.3%20Event%20Flow.jpg)
Netty 還提供了一組豐富的預定義的處理程序,您可以開箱即用。這些是各種協議的編解碼器包括 HTTP 和 SSL/TLS。在內部,ChannelHandler 使用事件和 future 本身,使得消費者的具有 Netty 的抽象。
### [](https://github.com/waylau/essential-netty-in-action/blob/master/GETTING%20STARTED/Building%20Blocks.md#整合)整合
#### [](https://github.com/waylau/essential-netty-in-action/blob/master/GETTING%20STARTED/Building%20Blocks.md#future-callback-和-handler)FUTURE, CALLBACK 和 HANDLER
Netty 的異步編程模型是建立在 future 和 callback 的概念上的。所有這些元素的協同為自己的設計提供了強大的力量。
攔截操作和轉換入站或出站數據只需要您提供回調或利用 future 操作返回的。這使得鏈操作簡單、高效,促進編寫可重用的、通用的代碼。一個 Netty 的設計的主要目標是促進“關注點分離”:你的業務邏輯從網絡基礎設施應用程序中分離。
#### [](https://github.com/waylau/essential-netty-in-action/blob/master/GETTING%20STARTED/Building%20Blocks.md#selector-event-和-event-loop)SELECTOR, EVENT 和 EVENT LOOP
Netty 通過觸發事件從應用程序中抽象出 Selector,從而避免手寫調度代碼。EventLoop 分配給每個 Channel 來處理所有的事件,包括
* 注冊有趣的事件
* 調度事件到 ChannelHandler
* 安排進一步行動
該 EventLoop 本身是由只有一個線程驅動,它給一個 Channel 處理所有的 I/O 事件,并且在 EventLoop 的生命周期內不會改變。這個簡單而強大的線程模型消除你可能對你的 ChannelHandler 同步的任何關注,這樣你就可以專注于提供正確的回調邏輯來執行。該 API 是簡單和緊湊。
- Introduction
- 開始
- Netty-異步和數據驅動
- Netty 介紹
- 構成部分
- 關于本書
- 第一個 Netty 應用
- 設置開發環境
- Netty 客戶端/服務端 總覽
- 寫一個 echo 服務器
- 寫一個 echo 客戶端
- 編譯和運行 Echo 服務器和客戶端
- 總結
- Netty 總覽
- Netty 快速入門
- Channel, Event 和 I/O
- 什么是 Bootstrapping 為什么要用
- ChannelHandler 和 ChannelPipeline
- 近距離觀察 ChannelHandler
- 總結
- 核心功能
- Transport(傳輸)
- 案例研究:Transport 的遷移
- Transport API
- 包含的 Transport
- Transport 使用情況
- 總結
- Buffer(緩沖)
- Buffer API
- ByteBuf - 字節數據的容器
- 字節級別的操作
- ByteBufHolder
- ByteBuf 分配
- 總結
- ChannelHandler 和 ChannelPipeline
- ChannelHandler 家族
- ChannelPipeline
- ChannelHandlerContext
- 總結
- Codec 框架
- 什么是 Codec
- Decoder(解碼器)
- Encoder(編碼器)
- 抽象 Codec(編解碼器)類
- 總結
- 提供了的 ChannelHandler 和 Codec
- 使用 SSL/TLS 加密 Netty 程序
- 構建 Netty HTTP/HTTPS 應用
- 空閑連接以及超時
- 解碼分隔符和基于長度的協議
- 編寫大型數據
- 序列化數據
- 總結
- Bootstrap 類型
- 引導客戶端和無連接協議
- 引導服務器
- 從 Channel 引導客戶端
- 在一個引導中添加多個 ChannelHandler
- 使用Netty 的 ChannelOption 和屬性
- 關閉之前已經引導的客戶端或服務器
- 總結
- 引導
- Bootstrap 類型
- 引導客戶端和無連接協議
- 引導服務器
- 從 Channel 引導客戶端
- 在一個引導中添加多個 ChannelHandler
- 使用Netty 的 ChannelOption 和屬性
- 關閉之前已經引導的客戶端或服務器
- 總結
- NETTY BY EXAMPLE
- 單元測試
- 總覽
- 測試 ChannelHandler
- 測試異常處理
- 總結
- WebSocket
- WebSocket 程序示例
- 添加 WebSocket 支持
- 測試程序
- 總結
- SPDY
- SPDY 背景
- 示例程序
- 實現
- 啟動 SpdyServer 并測試
- 總結
- 通過 UDP 廣播事件
- UDP 基礎
- UDP 廣播
- UDP 示例
- EventLog 的 POJO
- 寫廣播器
- 寫監視器
- 運行 LogEventBroadcaster 和 LogEventMonitor
- 總結
- 高級主題
- 實現自定義的編解碼器
- 編解碼器的范圍
- 實現 Memcached 編解碼器
- 了解 Memcached 二進制協議
- Netty 編碼器和解碼器
- 測試編解碼器
- EventLoop 和線程模型
- 線程模型的總覽
- EventLoop
- EventLoop
- I/O EventLoop/Thread 分配細節
- 總結
- 用例1:Droplr Firebase 和 Urban Airship
- 用例2:Facebook 和 Twitter