1. 程式人生 > >003——Netty之Buffer、Channel以及多路複用器Selector

003——Netty之Buffer、Channel以及多路複用器Selector

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;
        }
    }
    
    ...省略
}

image
(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 寫入資料。

image

為什麼Netty重寫Channel?

  • [1]Channel是Netty的核心,為了能夠與整體架構融合在一起。(待確定)

參考

[1] http://ifeve.com/java-nio-all/


多路複用器Selector

Selector會不斷輪詢註冊在其上的Channel,當某個Channel上發生事件,該Channel就處於就緒狀態,會被輪詢出來進行後續IO操作。

通過一個執行緒(多路複用器)Selector可以同時輪詢多個Channel,不必一個連線一個執行緒以一對一的形式應對請求,極大地減少系統開銷。

image
當讀或寫事件發生時,就會從Selector中獲取想用的SelectorKey,SelectionKey中可以找到發生的事件和該事件所發生的具體的SelectableChannel,以獲得客戶端傳送過來的資料.

NIO服務端

image