## 什么是 Netty
Netty 是一個利用 Java 的高級網絡的能力,隱藏其背后的復雜性而提供一個易于使用的 API 的客戶端/服務器框架。Netty 提供高性能和可擴展性,讓你可以自由地專注于你真正感興趣的東西,你的獨特的應用!
在這一章我們將解釋 Netty 在處理一些高并發的網絡問題體現的價值。然后,我們將介紹基本概念和構成 Netty 的工具包,我們將在這本書的其余部分深入研究。
## [](https://github.com/waylau/essential-netty-in-action/blob/master/GETTING%20STARTED/Asynchronous%20and%20Event%20Driven.md#一些歷史)一些歷史
在網絡發展初期,需要花很多時間來學習 socket 的復雜,尋址等等,在 C socket 庫上進行編碼,并需要在不同的操作系統上做不同的處理。
Java 早期版本(1995-2002)介紹了足夠的面向對象的糖衣來隱藏一些復雜性,但實現復雜的客戶端-服務器協議仍然需要大量的樣板代碼(和進行大量的監視才能確保他們是對的)。
這些早期的 Java API(java.net)只能通過原生的 socket 庫來支持所謂的“blocking(阻塞)”的功能。一個簡單的例子
Listing 1.1 Blocking I/O Example
~~~
ServerSocket serverSocket = new ServerSocket(portNumber);//1
Socket clientSocket = serverSocket.accept(); //2
BufferedReader in = new BufferedReader( //3
new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true);
String request, response;
while ((request = in.readLine()) != null) { //4
if ("Done".equals(request)) { //5
break;
}
}
response = processRequest(request); //6
out.println(response); //7
//8
~~~
1.ServerSocket 創建并監聽端口的連接請求
2.accept() 調用阻塞,直到一個連接被建立了。返回一個新的 Socket 用來處理 客戶端和服務端的交互
3.流被創建用于處理 socket 的輸入和輸出數據。BufferedReader 讀取從字符輸入流里面的本文。PrintWriter 打印格式化展示的對象讀到本文輸出流
4.處理循環開始 readLine() 阻塞,讀取字符串直到最后是換行或者輸入終止。
5.如果客戶端發送的是“Done”處理循環退出
6.執行方法處理請求,返回服務器的響應
7.響應發回客戶端
8.處理循環繼續
顯然,這段代碼限制每次只能處理一個連接。為了實現多個并行的客戶端我們需要分配一個新的 Thread 給每個新的客戶端 Socket(當然需要更多的代碼)。但考慮使用這種方法來支持大量的同步,長連接。在任何時間點多線程可能處于休眠狀態,等待輸入或輸出數據。這很容易使得資源的大量浪費,對性能產生負面影響。當然,有一種替代方案。
除了示例中所示阻塞調用,原生 socket 庫同時也包含了非阻塞 I/O 的功能。這使我們能夠確定任何一個 socket 中是否有數據準備讀或寫。我們還可以設置標志,因為讀/寫調用如果沒有數據立即返回;就是說,如果一個阻塞被調用后就會一直阻塞,直到處理完成。通過這種方法,會帶來更大的代碼的復雜性成本,其實我們可以獲得更多的控制權來如何利用網絡資源。
## [](https://github.com/waylau/essential-netty-in-action/blob/master/GETTING%20STARTED/Asynchronous%20and%20Event%20Driven.md#java-nio)JAVA NIO
在 2002 年,Java 1.4 引入了非阻塞 API 在 java.nio 包(NIO)。
*"New"還是"Nonblocking"?*
*NIO 最初是為 New Input/Output 的縮寫。然而,Java 的 API 已經存在足夠長的時間,它不再是新的。現在普遍使用的縮寫來表示Nonblocking I/O (非阻塞 I/O)。另一方面,一般(包括作者)指阻塞 I/O 為 OIO 或 Old Input/Output。你也可能會遇到普通 I/O。*
我們已經展示了在 Java 的 I/O 阻塞一例例子。圖 1.1 展示了方法 必須擴大到處理多個連接:給每個連接創建一個線程,有些連接是空閑的!顯然,這種方法的可擴展性將是受限于可以在 JVM 中創建的線程數。
Figure 1.1 Blocking I/O
[](https://github.com/waylau/essential-netty-in-action/blob/master/images/Figure%201.1%20Blocking%20IO.jpg)
當你的應用中連接數比較少,這個方案還是可以接受。當并發連接超過10000 時,context-switching(上下文切換)開銷將是明顯的。此外,每個線程都有一個默認的堆棧內存分配了 128K 和 1M 之間的空間。考慮到整體的內存和操作系統需要處理 100000 個或更多的并發連接資源,這似乎是一個不理想的解決方案。
## [](https://github.com/waylau/essential-netty-in-action/blob/master/GETTING%20STARTED/Asynchronous%20and%20Event%20Driven.md#selector)SELECTOR
相比之下,圖1.2 顯示了使用非阻塞I/O,主要是消除了這些方法 約束。在這里,我們介紹了“Selector”,這是 Java 的無阻塞 I/O 實現的關鍵。
Figure 1.2 Nonblocking I/O
[](https://github.com/waylau/essential-netty-in-action/blob/master/images/Figure%201.2%20Nonblocking%20IO.jpg)
Selector 最終決定哪一組注冊的 socket 準備執行 I/O。正如我們之前所解釋的那樣,這 I/O 操作設置為非阻塞模式。通過通知,一個線程可以同時處理多個并發連接。(一個 Selector 由一個線程通常處理,但具體實施可以使用多個線程。)因此,每次讀或寫操作執行能立即檢查完成。總體而言,該模型提供了比 阻塞 I/O 模型 更好的資源使用,因為
* 可以用較少的線程處理更多連接,這意味著更少的開銷在內存和上下文切換上
* 當沒有 I/O 處理時,線程可以被重定向到其他任務上。
你可以直接用這些 Java API 構建的 NIO 建立你的應用程序,但這樣做 正確和安全是無法保證的。實現可靠和可擴展的 event-processing(事件處理器)來處理和調度數據并保證盡可能有效地,這是一個繁瑣和容易出錯的任務,最好留給專家 - Netty。
- 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