Netty 中使用 ByteBuf 代替 Java NIO 提供的 ByteBuffer 作為字節的容器。
一、索引
ByteBuf 提供兩個指針變量支持讀和寫操作,讀操作使用 readerIndex,寫操作使用 writerIndex。如下圖:
- 可丟棄字節,因為它們已經被讀
- 可讀字節,已寫入但還沒有被讀取
- 可寫字節
二、索引管理
- 調用 markReaderIndex(), markWriterIndex(), resetReaderIndex() 和 resetWriterIndex() 來設置和重新定位 readerIndex 和 writerIndex,
- 調用 readerIndex(int) 或 writerIndex(int) 將指針移動到指定的位置
- 調用 clear() 同時設置 readerIndex 和 writerIndex 為 0
三、查詢操作
可以使用以 ByteBufProcessor 為參數的方法,下面例子實現了尋找一個回車符( \r ):
1 ByteBuf in = (ByteBuf)msg; 2 int index = in.forEachByte(ByteProcessor.FIND_CR);
四、衍生的緩沖區
slice 方法和 copy 方法都能實現拷貝功能,但是它們有不同之處,下面兩個例子說明了它們的不同之處。
先看看 slice 的例子:
1 Charset utf8 = Charset.forName("UTF-8"); 2 ByteBuf buf = Unpooled.copiedBuffer("Netty in Action rocks!", utf8); 3 4 ByteBuf sliced = buf.slice(0, 14); // 創建從0開始到14的新slice 5 System.out.println(sliced.toString(utf8)); //打印 Netty in Action 6 7 buf.setByte(0, (byte) 'J'); //更新索引為0的字節 8 // 斷言成功,說明slice之后兩段數據共享 9 assert buf.getByte(0) == sliced.getByte(0);
這個說明 slice 返回的是原緩沖區的一個副本,共享同一片數據。因此若需要操作某段數據,使用 slice 方法。
下面來看看 copy 方法是如何不同的:
1 Charset utf8 = Charset.forName("UTF-8"); 2 ByteBuf buf = Unpooled.copiedBuffer("Netty in Action rocks!", utf8); 3 4 ByteBuf copy = buf.copy(0, 14); // 注意這里使用了copy 5 System.out.println(copy.toString(utf8)); 6 7 buf.setByte(0, (byte) 'J'); 8 // 斷言成功,說明原數據修改對copy不影響 9 assert buf.getByte(0) != copy.getByte(0);
可以看到,代碼幾乎是相同的,但所衍生的 ByteBuf 效果是不同的。
五、讀 / 寫操作
讀 / 寫操作主要有兩類:
- get() / set() 操作:從給定的索引開始,寫索引和讀索引保持不變
- read() / write() 操作:從給定的索引開始,根據字節訪問的數量,遞增當前的寫索引或讀索引。
需要特別注意上述兩類操作對於讀索引和寫索引的影響。
常見的 get() 操作如下:
常見的 set() 操作如下:
常見的 read() 操作如下:
每個 read() 方法都對應一個 write() 方法,如下:
六、更多操作
還有一些比較常用的方法如下: