1. 程式人生 > >《Netty 權威指南》—— NIO類庫簡介

《Netty 權威指南》—— NIO類庫簡介

宣告:本文是《Netty 權威指南》的樣章,感謝博文視點授權併發程式設計網站釋出樣章,

在介紹NIO程式設計之前,我們首先需要澄清一個概念,NIO到底是什麼的簡稱?有人稱之為New IO,因為它相對於之前的IO類庫是新增的,所以被稱為New IO,這是它的官方叫法。但是,由於之前老的IO類庫是阻塞IO,New IO類庫的目標就是要讓JAVA支援非阻塞IO,所以,更多的人喜歡稱之為非阻塞IO(Non-block IO),由於非阻塞IO更能夠體現NIO的特點,所以本書使用的NIO都指的是非阻塞IO。

與Socket類和ServerSocket類相對應,NIO也提供了SocketChannel和ServerSocketChannel兩種不同的套接字通道實現。這兩種新增的通道都支援阻塞和非阻塞兩種模式。阻塞模式使用非常簡單,但是效能和可靠性都不好,非阻塞模式正好相反。開發人員一般可以根據自己的需要來選擇合適的模式,一般來說,低負載、低併發的應用程式可以選擇同步阻塞IO以降低程式設計複雜度。但是對於高負載、高併發的網路應用,需要使用NIO的非阻塞模式進行開發。
下面的小節首先介紹NIO程式設計中的一些基本概念,然後通過NIO服務端的序列圖和原始碼講解,讓大家快速的熟悉NIO程式設計的關鍵步驟和API的使用。如果你已經熟悉了NIO程式設計,可以跳過2.3章節繼續學習後面的章節。

2.3.1. NIO類庫簡介

新的輸入/輸出 (NIO) 庫是在 JDK 1.4 中引入的。NIO 彌補了原來同步阻塞I/O 的不足,它在標準 Java 程式碼中提供了高速的、面向塊的 I/O。通過定義包含資料的類,以及通過以塊的形式處理這些資料,NIO 不用使用本機程式碼就可以利用底層優化,這是原來的 I/O 包所無法做到的。下面我們對NIO的一些概念和功能做下簡單介紹,以便大家能夠快速的瞭解NIO類庫和相關概念。

2.3.1.1. 緩衝區Buffer

我們首先介紹緩衝區(Buffer)的概念,Buffer 是一個物件, 它包含一些要寫入或者要讀出的資料。 在 NIO類庫 中加入 Buffer 物件,體現了新庫與原 I/O 的一個重要區別。在面向流的 I/O 中,我們將資料直接寫入或者將資料直接讀到 Stream 物件中。
在 NIO 庫中,所有資料都是用緩衝區進行處理的。在讀取資料時,它是直接讀到緩衝區中;在寫入資料時,它也是寫入到緩衝區中。任何時候訪問 NIO 中的資料,我們都是通過緩衝區進行讀寫操作。
緩衝區實質上是一個數組。通常它是一個位元組陣列(ByteBuffer),也可以使用其它種類的陣列。但是一個緩衝區不僅僅是一個數組,緩衝區提供了對資料的結構化訪問,及維護讀寫位置(limit)等資訊。
最常用的緩衝區是ByteBuffer,一個ByteBuffer提供了一組功能用於操作byte陣列。除了ByteBuffer,還有其它的一些緩衝區,事實上,每一種Java基本型別(除了Boolean型別)都對應有一種緩衝區,如下所示:

  • ByteBuffer:位元組緩衝區
  • CharBuffer:字元緩衝區
  • ShortBuffer:短整型緩衝區
  • IntBuffer:整形緩衝區
  • LongBuffer:長整形緩衝區
  • FloatBuffer:浮點型緩衝區
  • DoubleBuffer:雙精度浮點型緩衝區

緩衝區的類圖繼承關係如下所示:

3

Buffer繼承關係圖

每一個Buffer類都是Buffer介面的一個子例項。除了 ByteBuffer,每一個 Buffer 類都有完全一樣的操作,只是它們所處理的資料型別不一樣。因為大多數標準I/O操作都使用ByteBuffer,所以它除了具有一般緩衝區的操作之外還提供一些特有的操作,方便網路讀寫。

2.1.1.2. 通道Channel

Channel是一個通道,可以通過它讀取和寫入資料,它就像自來水管一樣,網路資料通過Channel讀取和寫入。通道與流的不同之處在於通道是雙向的。而流只是在一個方向上移動(一個流必須是 InputStream 或者 OutputStream 的子類),而通道可以用於讀、寫或者同時用於讀寫。

因為Channel是全雙工的,所以它可以比流更好地對映底層作業系統的API。特別是在UNIX網路程式設計模型中,底層作業系統的通道都是全雙工的,同時支援讀寫操作。

Channel的類圖繼承關係如下:

channel

Channel繼承關係類圖

自頂向下,前三層主要是Channel介面,用於定義它的功能,後面是一些具體的功能類(抽象類),從類圖可以看出,實際上Channel可以分為兩大類,分別是用於網路讀寫的SelectableChannel和用於檔案操作的FileChannel。

本書涉及的ServerSocketChannel和SocketChannel都是SelectableChannel的子類,關於它們的具體用法將在後續的程式碼中體現。

2.1.1.3.多路複用器Selector

在本節中,我們將探索多路複用器Selector,它是JAVA NIO程式設計的基礎,熟練的掌握Selector對於掌握NIO程式設計至關重要。多路複用器提供選擇已經就緒的任務的能力。簡單來講,Selector會不斷的輪詢註冊在其上的Channel,如果某個Channel上面有新的TCP連線接入、讀和寫事件,這個Channel就處於就緒狀態,會被Selector輪詢出來,然後通過SelectionKey可以獲取就緒Channel的集合進行後續的IO操作。

一個多路複用器Selector可以同時輪詢多個Channel,由於JDK使用了epoll()代替傳統的select實現,所以它並沒有最大連線控制代碼1024/2048的限制。這也就意味著只需要一個執行緒負責Selector的輪詢,就可以接入成千上萬的客戶端,這的確是一個巨大的改進。