Netty的字節容器ByteBuffer使用過於複雜,使用ByteBuf替代。
5.1 ByteBuf的API
詳見 abstract class ByteBuf 和 interface ByteBufHolder.
5.2
網絡通信涉及到字節序列的移動,所以高效易用的數據結構是很重要的。Netty的ByteBuf滿足並超越了這些需求。
5.2.1 工作原理
ByteBuf維護了兩個不同的索引,一個用於讀取,一個用於寫入。在名稱以read或者write開頭的ByteBuf方法,將會推進其對應的索引,而名稱以set或get開頭的操作則不會。
5.2.2 ByteBuf的使用模式
第一種模式 堆緩衝區
此模式將數據存儲在JVM的堆內存中,這種模式被稱爲支撐數組。她能在沒有使用池化的情況下提供快速的分配和釋放。
第二種模式 直接緩衝區
直接緩衝區中的內容將駐留在常規的,會被垃圾回收的堆之外。如果你的數據包含在一個堆上分配的緩衝區中,那麼事實上,在通過套接字發送之前,JVM將會在內部把你的緩衝區複製到一個直接緩衝區中。
第三種模式 複合緩衝區
複合緩衝區爲多個ByteBuf提供了一個聚合視圖。Netty通過ByteBuf的子類CompositeByByteBuf實現了這個模式。提供了一個將多個緩衝區表示爲單個合併緩衝區的虛擬表示。
5.3 字節級操作
5.3.1 隨機訪問索引
第一個字節的索引是0.最後一個自己的索引是capacity()-1
5.3.2 順序訪問索引
ByteBuf的會被其read索引和write分爲三部分。如下圖。
5.3.3 可丟棄字節
如如上圖,可丟棄的字節,包含了已經被讀過的字節。通過discardReadBytes()方法,可以丟棄他們並回收空間。但不建議頻繁調用這個防範。
5.3.4 可讀字節
這個部分,存儲了實際數據。通過readByte()進行讀取。並移動read索引。
5.3.5 可寫字節
指一個擁有未定義內容的,寫入就緒的內存區域。
5.3.6 索引管理
netty可以通過markReaderIndex(),markWriteIndex(),resetReaderIndex(),resetWriterIndex()來操作索引。
也可以通過readerIndex(index),writerIndex(index)來將索引移動到指定位置。clear(),將ReaderIndex和WriterIndex置爲0,它只是重置索引,並不會複製任何內存。
5.3.7 查找操作
indexOf() ,比較簡單,,
indexOf(ByteBufProcessor),這時需要自己實現其方法process,這個方法用於檢查輸入的值是否是正在查找的值。
netty還定義了一些簡答的查找操作,比如,包含以null結尾的內容可用buffer.forEachByte(ByteBufProcess.FIDN_NULL)
5.3.8 派生緩衝區
爲ByteBuf提供了以專門的方式來呈現其內容的視圖。有如下方法可以創建派生緩衝區。
- duplicate()
- slice()
- slice(int,int)
- Upooled,unmodifiableBuffer()
- order(ByteOrder)
- readSlice(int)
這些方法都將會返回一個新的ByteBuf實例,都會具有自己的讀索引,寫索引,標記索引。
5.3.9 讀寫操作
- get*(),set*(),從給定的索引開始,並且保持索引不變
- read*(),write*(). 從給定的索引開始,並且會根據已經訪問的字節數對索引進行調整。
5.3.10 其他方法
名稱 | 描述 |
---|---|
isReadable() | 如果至少有一個字節可供讀取 |
isWritable() | 如果至少有一個字段可寫入 |
readableBytes() | 返回可供讀取的字節數 |
writablebytes() | 返回可被寫入的字節數 |
capacity() | 返回ByteBuf 可容納的字節 |
maxCapacity() | 返回ByteBuf可以容納的最大字節數 |
hasArray() | 如果ByteBuf由一個字節數據支撐,返回true |
array() | 如果ByteBuf由一個字節數據支撐則返回該數據,否則拋UnsupportedOperationException |
5.4 ByteBufHolder 接口
ByteBufHolder爲Netty提供了高級特性,比如緩衝區池化。常用操作如下:
名稱 | 描述 |
---|---|
content() | 返回由這個ByteBufHolder所持有的ByteBuf |
copy() | 返回這個ByteBUfHolder的一個深拷貝,包含一個其所包含的ByteBuf的非共享拷貝 |
duplicate() | 返回這個ByteBufHolder的一個淺拷貝,包含一個其所包含的ByteBuf的共享拷貝 |
5.5 ByteBuf分配
介紹管理ByteBuf實例的不同方式。
5.5.1 ByteBufAllocator接口
Netty通過接口ByteBufAllocator實現了ByteBuf的池化,可用來分配我們所描述的熱議類型的ByteBuf實例。
常用APi:
名稱 | 描述 |
---|---|
buffer() | 返回一個基於堆或者直接內存存儲的ByteBuf |
heapBuffer | 返回一個基於堆內存存儲的ByteBuf |
directBuffer | 返回一個基於直接內存存儲的ByteBuf |
compositeBuffer | 返回一個可以通過添加最大到指定書目的基於堆的或者基於直接內存存儲的緩衝區來擴展的符合緩衝區 |
可以通過Channel(每個都可以有一個不同的ByteBufAllocator 實例)或者綁定到ChannelHandler 的ChannelHandlerContext 獲取一個到ByteBufAllocator 的引用
5.5.2 Unpooled緩衝區
提供了靜態的輔助方法來創建未池化的ByteBuf實例。有如下API:
名稱 | 描述 |
---|---|
buffer | 返回一個未池化的基於堆內存存儲的ByteBuf |
directBuffer | fa返回一個未池化的基於直接內存存儲的ByteBuf |
wrappedBuffer() | 返回一個包裝了給定數據的ByteBuf |
copiedBuffer() | 返回了一個複製了給定數據的ByteBuf |
5.5.3 ByteBufUtil類
提供了用於操作ByteBuf的靜態輔助方法。
hexdump(): 以十六進制的表示形式打印ByteBuf的內容。
5.5.6 引用計數
引用計數是一種通過在某個對象所持有的資源不再被其他對象應用時釋放該對象所持有的資源來優化內存使用和性能的技術。
最後
如果你覺得寫的還不錯,就關注下公衆號唄,關注後,有點小禮物回贈給你。
你可以獲得5000+電子書,java,springCloud,adroid,python等各種視頻教程,IT類經典書籍,各種軟件的安裝及破解教程。
希望一塊學習,一塊進步!