【Netty】NIO 緩衝區 Buffer 組件 ( NIO 三大組件關係 | Buffer 類 | Buffer 機制 | Buffer 常用方法 | ByteBuffer 常用方法 )





I . NIO 三大核心組件 對應關係



下圖是 NIO 三大核心組件 , 選擇器 ( Selector ) , 通道 ( Channel ) , 緩衝區 ( Buffer ) , 與 服務器端線程 , 客戶端 , 結構圖 ;

在這裏插入圖片描述

1 . 解析上圖 NIO 核心組件對應關係 :


① 通道 緩衝區 對應 : 每個 通道 ( Channel ) 都對應一個 緩衝區 ( Buffer ) ;

② 選擇器 通道 關聯方式 : 每個 選擇器 ( Selector ) 對應多個 通道 ( Channel ) , 通道 ( Channel ) 是通過註冊的方式 , 註冊給 選擇器 ( Selector ) ;

③ 選擇器 線程 對應 : 每個 選擇器 ( Selector ) 對應一個線程 ;

④ 線程 通道 對應 : 每個線程 對應多個 通道 ( Channel ) ;



2 . 引申要素分析 :


① BIO 單向流機制 : BIO 中使用 Socket 進行通信時 , 每個流都是 單向 的 , 輸入流只能讀取數據 , 不能寫出數據 ; 輸出流只能寫出數據 , 不能讀取數據 ;

② 緩衝區 ( Buffer ) 本質 : 緩衝區 ( Buffer ) 本質是一個數組 ;

③ 緩衝區 ( Buffer ) 雙向機制 : NIO 中的 緩衝區 ( Buffer ) 是 雙向 的 , 既可以讀取數據 , 又可以寫出數據 , 但是注意讀寫的方向是相反的 , 讀取狀態 轉爲 寫出狀態時 , 需要調用 flip() 方法翻轉 緩衝區 ( Buffer ) ;

④ 通道 ( Channel ) 雙向機制 : 通道 ( Channel ) 負責讀寫 緩衝區 ( Buffer ) , 因此 通道 ( Channel ) 也必須是雙向的 ;

⑤ 事件 ( Event ) : 事件 ( Event ) 決定 選擇器 ( Selector ) 選擇哪條 通道 ( Channel ) , 決定線程 爲哪個 通道 ( Channel ) 服務 ;





II . 緩衝區 ( Buffer ) 類



Buffer 常用子類 :

  • ByteBuffer : 字節 緩衝區 ;
  • ShortBuffer : 短整型 緩衝區 ;
  • CharBuffer : 字符 緩衝區 ;
  • IntBuffer : 整型 緩衝區 ;
  • LongBuffer : 長整型 緩衝區 ;
  • DoubleBuffer : 雙精度浮點型 緩衝區 ;
  • FloatBuffer : 單精度浮點型 緩衝區 ;

上述 ByteBuffer 使用頻率最高 , 一般情況下 , 傳輸數據使用 ByteBuffer 進行數據的傳輸 ;





III . 緩衝區 ( Buffer ) 機制



緩衝區 ( Buffer ) : 緩衝區 ( Buffer ) 是 在內存中開闢出一塊內存 , 並提供一組 API 專門用於讀寫內存中的數據 ;


緩衝區 ( Buffer ) 機制 : 其內部提供了一系列機制 , 如記錄當前的操作 ( 讀取 / 寫出 ) 位置 等實時信息 ;



緩衝區 ( Buffer ) 標誌位 :


① mark : 標記 , 用途由開發者自定義 ;

② position : 標識當前數組索引 ;

③ limit : 緩衝區當前的限制大小 , 如果當前的 position 大於 limit 值 , 無法進行讀寫操作 , 該值可以修改 ;

④ capacity : 緩衝區 ( Buffer ) 容量 , 緩衝區創建時設置 , 無法修改該容量值 ;


mark \leq position \leq limit \leq capacity





IV . 緩衝區 ( Buffer ) 機制 示例解析



解析 緩衝區 ( Buffer ) 機制 , 逐步 Debug 代碼 , 及給出每個步驟的示意圖 , 解析過程中的 1 . 2 . 3 . 標號與代碼中的標號一致 ;


public class BufferDemo {
    public static void main(String[] args) {
        //1 . 創建一個存儲 Int 類型數據的 Buffer , 可以存儲 8 個 Int 數據
        IntBuffer buffer = IntBuffer.allocate(8);

        //2 . 設置 只 讀寫 3 個元素
        buffer.limit(3);

        //3 . 向 Buffer 中寫入數據
        for(int i = 0; i < buffer.limit(); i ++){
            buffer.put(i);
        }

        //從 Buffer 中取出數據
        //4 . 先將 Buffer 翻轉一下 , 然後讀取 , 讀出的數據與存儲的數據順序一樣
        buffer.flip();

        //5 . 循環讀取 buffer 中的 Int 數據, 維護了一個索引 ,
        //代表當前操作的數據索引 , 即 position
        while (buffer.hasRemaining()){
            System.out.println("position " + buffer.position() + " . " + buffer.get());
        }
    }
}

1 . 創建 Buffer 緩衝區 : 此時創建了一個空的緩衝區 , 88 個元素默認初始化爲 0 , position00 , limitcapacity88 ;

在這裏插入圖片描述
在這裏插入圖片描述


2 . 設置 limit 限制 : 只使用 88 個容器中的 33 個 , 如果 position \geq 3 , 讀寫時報異常 ;

在這裏插入圖片描述

在這裏插入圖片描述


3 . 向 Buffer 中寫入數據 :


① 向 Buffer 中寫入 00 : 寫入後 , position 變爲 11 , 第 0 個元素變爲 0 ( 看不出來 ) ;

在這裏插入圖片描述
在這裏插入圖片描述


② 向 Buffer 中寫入 11 : 寫入後 , position 變爲 22 , 第 1 個元素變爲 1 ;

在這裏插入圖片描述

在這裏插入圖片描述


③ 向 Buffer 中寫入 22 : 寫入後 , position 變爲 33 , 第 2 個元素變爲 2 ; 此時 position \geq limit , 如果在讀寫緩衝區 , 就要崩潰了 , 退出循環 , 執行下面的操作 ;

在這裏插入圖片描述

在這裏插入圖片描述


4 . 翻轉操作 : 將當前的 position 33 設置成 limit , 然後將 position 設置成 00 , 清除 mark 值 ( 這裏沒有 ) ;

在這裏插入圖片描述
在這裏插入圖片描述


5 . 讀取 緩衝區 ( Buffer ) 數據 :


① 讀取 第 00 個數據 : 讀取到 00 , position 變爲 11 ;

在這裏插入圖片描述
在這裏插入圖片描述

② 讀取 第 11 個數據 : 讀取到 11 , position 變爲 22 ;

在這裏插入圖片描述

在這裏插入圖片描述


③ 讀取 第 11 個數據 : 讀取到 22 , position 變爲 33 ; 至此 , 程序全部執行完畢 ;

在這裏插入圖片描述
在這裏插入圖片描述





V . 緩衝區 ( Buffer ) 提供的方法



Buffer 是抽象類 , 是所有的 緩衝區類的父類 , 其提供的以下方法 , 在其它 77 個類中都可以使用 ;


與標誌位相關方法 :

  • int capacity() : 獲取緩衝區容量 ;
  • int position() : 獲取緩衝區當前讀取或寫出的索引位置 , 每讀取 / 寫出 一個元素 , 位置都會自增 , 指向下一個將要讀取 / 寫出的位置 ;
  • Buffer position (int newPosition) : 強行設置緩衝區的位置 , 跳轉到指定的位置讀取或寫出數據 ;
  • int limit() : 獲取緩衝區可操作性限制大小 ;
  • Buffer limit(int newLimit) : 設置緩衝區的新的可操作限制大小 ;
  • Buffer mark() : 將當前的 position 設置爲 mark ;
  • Buffer reset() : 將 position 設置成 mark 的位置 ;

緩衝區變換相關方法 :

  • Buffer clear() : 清除緩衝區的四大標誌位 , 緩衝區的數據保持不變 ;
  • Buffer flip() : 翻轉操作 , limit 設置成當前 position 值 , position 設置爲 0, mark 清除 ;
  • Buffer rewind() : 重繞操作 ;
  • Buffer remaining() : 獲取當前 position 和 limit 的差值 ;

判定相關方法 :

  • boolean hasRemaining() : position 和 limit 是否相等 , 之間還有沒有元素 ;
  • boolean isReadOnly() : 當前緩衝區是否是可讀緩衝區 ;
  • boolean isDirect() : 該緩衝區是否是直接緩衝區 ;

數組相關 :

  • boolean hasArray() : 該緩衝區的底層實現數組是否可以訪問 ;
  • Object array() : 獲取緩衝區的底層數組 ;
  • int arrayOffset() : 獲取 緩衝區第一個元素在底層數組中的索引 ;




VI . 字節緩衝區 ( ByteBuffer ) 提供的方法



字節緩衝區 ( ByteBuffer ) 是最常用的緩衝區 , 一般在客戶端與服務器端交互使用的最多的就是字節緩衝區 ;

ByteBuffer 是 Buffer 的派生類 , 因此上面的 Buffer 中的所有方法都可以在 ByteBuffer 中使用 ;


緩衝區構建相關 API :

  • ByteBuffer allocateDirect(int capacity) : 創建直接字節緩衝區 , 並指定緩衝區大小 ;
  • ByteBuffer allocate(int capacity) : 創建字節緩衝區 , 並指定緩衝區大小 ;
  • ByteBuffer wrap(byte[] array) : 創建字節緩衝區 , 將 byte 數組放入緩衝區中 ;
  • ByteBuffer wrap(byte[] array , int offset , int length) : 創建字節緩衝區 , 將 byte 數組 的 第 offset 個元素開始的 length 個元素 放入緩衝區中 ;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章