003——Netty之Buffer、Channel以及多路複用器Selector
阿新 • • 發佈:2018-11-25
Buffer
1、緩衝區型別
2、緩衝區定義
(1)Buffer是一個物件,其中包含寫入與讀出的資料。是新IO與原IO的重要區別。任何情況下訪問NIO中的資料都需要通過快取區進行操作。
(2)Buffer在程式碼中體現就是一個數組,本質上就是記憶體中的一塊區域。
Buffer原始碼
public abstract class Buffer { // Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private int capacity; // Used only by direct buffers // NOTE: hoisted here for speed in JNI GetDirectBufferAddress long address; // Creates a new buffer with the given mark, position, limit, and capacity, // after checking invariants. // Buffer(int mark, int pos, int lim, int cap) { // package-private if (cap < 0) throw new IllegalArgumentException("Negative capacity: " + cap); this.capacity = cap; limit(lim); position(pos); if (mark >= 0) { if (mark > pos) throw new IllegalArgumentException("mark > position: (" + mark + " > " + pos + ")"); this.mark = mark; } } ...省略 }
(1)BUffer的四個屬性。mark、position、limit、capacity。
[1] capacity:快取區容量。設定即不可更改,比如 capacity 為 1024 的 IntBuffer,代表其一次可以存放 1024 個 int 型別的值。當Buffer 的容量達到 capacity,需要清空 Buffer,才能重新寫入值。
[2] limit:寫模式是記錄最大能夠寫入的資料。讀模式下limit等於Buffer實際大小。
[3] position:寫模式下position初始值為0,當寫入一個值時,position+1,指向下次寫入位置。讀模式下position會置0,這時將會從頭開始讀取Buffer中的資料。
[4] mark:Buffer#mark()記錄當前position值,用於讀寫切換時還原position值。
(2)Netty提供了兩個指標變數用於讀寫操作。分別是readerIndex與writeIndex。
+-------------------+------------------+------------------+ | discardable bytes | readable bytes | writable bytes | | | (CONTENT) | | +-------------------+------------------+------------------+ | | | | 0 <= readerIndex <= writerIndex <= capacity
[1] readerIndex 到 writeIndex為可讀度的位元組快取區。
[2] writeIndex 到 capacity為可寫的位元組快取區
[3] 0 到 readerIndex為已讀位元組快取區
Channel
Channel定義
通道是資料來源與資料寫入的目的地。主要分為以下幾種,分別是FileChannel(檔案通道,用於檔案的讀和寫
)、DatagramChannel(用於 UDP 連線的接收和傳送)、SocketChannel(把它理解為 TCP 連線通道,簡單理解就是 TCP 客戶端)、ServerSocketChannel(TCP 對應的服務端,用於監聽某個埠進來的請求)
NIO Channel與Java stream區別
- 對於同一個 Channel全雙工,Stream(InputStream、OutputStream)要麼讀要麼寫
- Channel 可以非阻塞的讀寫 IO 操作,而 Stream 只能阻塞的讀寫 IO 操作。
- Channel 必須配合 Buffer 使用,總是先讀取到一個 Buffer 中,又或者是向一個 Buffer 寫入。也就是說,我們無法繞過 Buffer ,直接向 Channel 寫入資料。
為什麼Netty重寫Channel?
- [1]Channel是Netty的核心,為了能夠與整體架構融合在一起。(待確定)
參考
[1] http://ifeve.com/java-nio-all/
多路複用器Selector
Selector會不斷輪詢註冊在其上的Channel,當某個Channel上發生事件,該Channel就處於就緒狀態,會被輪詢出來進行後續IO操作。
通過一個執行緒(多路複用器)Selector可以同時輪詢多個Channel,不必一個連線一個執行緒以一對一的形式應對請求,極大地減少系統開銷。
當讀或寫事件發生時,就會從Selector中獲取想用的SelectorKey,SelectionKey中可以找到發生的事件和該事件所發生的具體的SelectableChannel,以獲得客戶端傳送過來的資料.