Netty ByteBuf梳理


我們知道,網絡數據的基本單位總是字節。Java NIO提供了ByteBuffer作為它的字節容器,但是這個類使用起來過於復雜,而且也有些繁瑣。
Netty的ByteBuffer替代品是ByteBuf,一個強大的實現,既解決了JDK API的局限性,又為網絡應用程序的開發者提供了更好的API。

ByteBuf的API

Netty的數據處理API通過兩個組件暴露——abstract class ByteBuf和interface ByteBufHolder。
下面是一些ByteBuf API的優點:

  • 它可以被用戶自定義的緩沖區類型擴展;
  • 通過內置的復合緩沖區類型實現了透明的零拷貝;
  • 容量可以按需增長(類似於JDK的StringBuilder);
  • 在讀和寫這兩種模式之間切換不需要調用ByteBuffer的flip()方法;
  • 讀和寫使用了不同的索引;
  • 支持方法的鏈式調用;
  • 支持引用計數;
  • 支持池化。
    其他可以用於管理ByteBuffer實例的分配,以及執行各種針對於數據容器本身和它所持有的數據的操作。

因為所有的網絡通信都涉及字節序列的移動,所以高效易用的數據結構明顯是必不可少的。Nety的ByteBuf實現滿足並超越了這些需求。
ByteBuf維護了兩個不同的索引:一個用於讀取,一個用於寫入。當你從ByteBuf讀取時,它的readIndex將會被遞增已經被讀取的字節數。同樣的,當你寫入ByteBuf時,它的writeIndex也會被遞增。
要了解這些索引兩兩之間的關系,如果打算讀取字節直到radIndex達到writeIndex同樣的值,你將會到達“可以讀取的”數據的末尾。如果試圖讀取超過改點的數據將會觸發一個IndexOutOfBoundsException。
名稱為read或者write開頭的ByteBuf方法,將會推進其對應的索引,而名稱以ste或get開頭的操作則不會。后面的這些方法將在作為一個參數傳入的一個相對索引上執行操作。

ByteBufHolder接口

我們經常發現,除了實際的數據負載之外,我們還需要存儲各種屬性值。HTTP響應便是一個很好的例子,除了表示為字節的內容,還包括狀態碼、cookie等。
為了處理這種常見的用例,Netty提供了ByteBufHolder。ByteBufHolder也為Netty的高級特性提供了支持,入緩沖區池化,其中可以從池中借用ByteBuf,並且在需要時自動釋放。
ByteBufHolder只有幾種用於訪問底層數據和引用計數的方法。

名稱 描述
content() 返回由這個ByteBufHolder所持有的ByteBuf
copy() 返回這個ByteBufHolder得一個深拷貝,包括一個其所包含的ByteBuf的非共享拷貝
duplicate() 返回這個ByteBufHolder的以個淺拷貝,包括一個其所包含的ByteBuf的共享拷貝

如果想要實現一個將其有效負載存儲在ByteBuf中的消息對象,那么ByteBufHolder將是個不錯的選擇。

ByteBuf分配

  • 按需分配:ByteBufAllocator接口
    為了降低分配和釋放內存的開銷,Netty通過interface ByteBufAllocator實現了(ByteBuf的)池化,它可以用來分配我們所描述過的任意類型的ByteBuf實例。使用池化是應用程序的決定,其並不會以任何方式改變ByteBuf API(的語義)。
    可以通過Channel(每一個可以有一個不同的ByteBufAllocator的實例)或者綁定到ChannelHandler的ChannelHnadlerContext獲取一個到ByteBufAlocator的引用。
Channel channel = ... ;
ByteBufAllocator allocator = channel.alloc();
...
ChannelHandlerContext ctx = ... ;
ByteBufAllocator allocator2 = ctx.alloc();
...

  • Unpooled緩沖區
    可能某些情況下,你未能獲取一個到ByteBufAllocator的引用。對於這種情況,Netty提供了一個簡單地稱為Unpooled的工具類,它提供了靜態的輔助方法來創建未池化的ByteBuf實例。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM