W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
既然所有的網絡通信都是要基于底層的字節(jié)流來傳輸,那么傳輸所使用的數據接口就要求是效率高得、使用方便的而且容易使用的,Netty的ByteBuf更好能夠達到這些要求。
ByteBuf 是一個已經經過優(yōu)化的很好使用的數據容器,字節(jié)數據可以有效的被添加到 ByteBuf 中或者也可以從 ByteBuf 中直接獲取數據。ByteBuf中有兩個索引:一個用來讀,一個用來寫。這兩個索引達到了便于操作的目的。我們可以按順序的讀取數據,也可以通過調整讀取數據的索引或者直接將讀取位置索引作為參數傳遞給get方法來重復讀取數據。
寫入數據到 ByteBuf 后,writerIndex(寫入索引)增加寫入的字節(jié)數。讀取字節(jié)后,readerIndex(讀取索引)也增加讀取出的字節(jié)數。你可以讀取字節(jié),直到寫入索引和讀取索引處在相同的位置。此時ByteBuf不可讀,所以下一次讀操作將會拋出 IndexOutOfBoundsException,就像讀取數組時越位一樣。
調用 ByteBuf 的以 "read" 或 "write" 開頭的任何方法都將自動增加相應的索引。另一方面,"set" 、 "get"操作字節(jié)將不會移動索引位置,它們只會在指定的相對位置上操作字節(jié)。
可以給ByteBuf指定一個最大容量值,這個值限制著ByteBuf的容量。任何嘗試將寫入超過這個值的數據的行為都將導致拋出異常。ByteBuf 的默認最大容量限制是 Integer.MAX_VALUE。
ByteBuf 類似于一個字節(jié)數組,最大的區(qū)別是讀和寫的索引可以用來控制對緩沖區(qū)數據的訪問。下圖顯示了一個容量為16的空的 ByteBuf 的布局和狀態(tài),writerIndex 和 readerIndex 都在索引位置 0 :
最常用的模式是 ByteBuf 將數據存儲在 JVM 的堆空間,這是通過將數據存儲在數組的實現。堆緩沖區(qū)可以快速分配,當不使用時也可以快速釋放。它還提供了直接訪問數組的方法,通過 ByteBuf.array() 來獲取 byte[]數據。 這種方法,正如清單5.1中所示的那樣,是非常適合用來處理遺留數據的。
Listing 5.1 Backing array
ByteBuf heapBuf = ...;
if (heapBuf.hasArray()) { //1
byte[] array = heapBuf.array(); //2
int offset = heapBuf.arrayOffset() + heapBuf.readerIndex(); //3
int length = heapBuf.readableBytes();//4
handleArray(array, offset, length); //5
}
1.檢查 ByteBuf 是否有支持數組。
2.如果有的話,得到引用數組。
3.計算第一字節(jié)的偏移量。
4.獲取可讀的字節(jié)數。
5.使用數組,偏移量和長度作為調用方法的參數。
注意:
“直接緩沖區(qū)”是另一個 ByteBuf 模式。對象的所有內存分配發(fā)生在 堆,對不對?好吧,并非總是如此。在 JDK1.4 中被引入 NIO 的ByteBuffer 類允許 JVM 通過本地方法調用分配內存,其目的是
這就解釋了為什么“直接緩沖區(qū)”對于那些通過 socket 實現數據傳輸的應用來說,是一種非常理想的方式。如果你的數據是存放在堆中分配的緩沖區(qū),那么實際上,在通過 socket 發(fā)送數據之前,JVM 需要將先數據復制到直接緩沖區(qū)。
但是直接緩沖區(qū)的缺點是在內存空間的分配和釋放上比堆緩沖區(qū)更復雜,另外一個缺點是如果要將數據傳遞給遺留代碼處理,因為數據不是在堆上,你可能不得不作出一個副本,如下:
Listing 5.2 Direct buffer data access
ByteBuf directBuf = ...
if (!directBuf.hasArray()) { //1
int length = directBuf.readableBytes();//2
byte[] array = new byte[length]; //3
directBuf.getBytes(directBuf.readerIndex(), array); //4
handleArray(array, 0, length); //5
}
1.檢查 ByteBuf 是不是由數組支持。如果不是,這是一個直接緩沖區(qū)。
2.獲取可讀的字節(jié)數
3.分配一個新的數組來保存字節(jié)
4.字節(jié)復制到數組
5.將數組,偏移量和長度作為參數調用某些處理方法
顯然,這比使用數組要多做一些工作。因此,如果你事前就知道容器里的數據將作為一個數組被訪問,你可能更愿意使用堆內存。
最后一種模式是復合緩沖區(qū),我們可以創(chuàng)建多個不同的 ByteBuf,然后提供一個這些 ByteBuf 組合的視圖。復合緩沖區(qū)就像一個列表,我們可以動態(tài)的添加和刪除其中的 ByteBuf,JDK 的 ByteBuffer 沒有這樣的功能。
Netty 提供了 ByteBuf 的子類 CompositeByteBuf 類來處理復合緩沖區(qū),CompositeByteBuf 只是一個視圖。
警告
CompositeByteBuf.hasArray() 總是返回 false,因為它可能既包含堆緩沖區(qū),也包含直接緩沖區(qū)
例如,一條消息由 header 和 body 兩部分組成,將 header 和 body 組裝成一條消息發(fā)送出去,可能 body 相同,只是 header 不同,使用CompositeByteBuf 就不用每次都重新分配一個新的緩沖區(qū)。下圖顯示CompositeByteBuf 組成 header 和 body:
Figure 5.2 CompositeByteBuf holding a header and body
下面代碼顯示了使用 JDK 的 ByteBuffer 的一個實現。兩個 ByteBuffer 的數組創(chuàng)建保存消息的組件,第三個創(chuàng)建用于保存所有數據的副本。
Listing 5.3 Composite buffer pattern using ByteBuffer
// 使用數組保存消息的各個部分
ByteBuffer[] message = { header, body };
// 使用副本來合并這兩個部分
ByteBuffer message2 = ByteBuffer.allocate(
header.remaining() + body.remaining());
message2.put(header);
message2.put(body);
message2.flip();
這種做法顯然是低效的;分配和復制操作不是最優(yōu)的方法,操縱數組使代碼顯得很笨拙。
下面看使用 CompositeByteBuf 的改進版本
Listing 5.4 Composite buffer pattern using CompositeByteBuf
CompositeByteBuf messageBuf = ...;
ByteBuf headerBuf = ...; // 可以支持或直接
ByteBuf bodyBuf = ...; // 可以支持或直接
messageBuf.addComponents(headerBuf, bodyBuf);
// ....
messageBuf.removeComponent(0); // 移除頭 //2
for (int i = 0; i < messageBuf.numComponents(); i++) { //3
System.out.println(messageBuf.component(i).toString());
}
1.追加 ByteBuf 實例的 CompositeByteBuf
2.刪除 索引1的 ByteBuf
3.遍歷所有 ByteBuf 實例。
清單5.4 所示,你可以簡單地把 CompositeByteBuf 當作一個可迭代遍歷的容器。 CompositeByteBuf 不允許訪問其內部可能存在的支持數組,也不允許直接訪問數據,這一點類似于直接緩沖區(qū)模式,如圖5.5所示。
Listing 5.5 Access data
CompositeByteBuf compBuf = ...;
int length = compBuf.readableBytes(); //1
byte[] array = new byte[length]; //2
compBuf.getBytes(compBuf.readerIndex(), array); //3
handleArray(array, 0, length); //4
1.得到的可讀的字節(jié)數。
2.分配一個新的數組,數組長度為可讀字節(jié)長度。
3.讀取字節(jié)到數組
4.使用數組,把偏移量和長度作為參數
Netty 嘗試使用 CompositeByteBuf 優(yōu)化 socket I/O 操作,消除 原生 JDK 中可能存在的的性能低和內存消耗問題。雖然這是在Netty 的核心代碼中進行的優(yōu)化,并且是不對外暴露的,但是作為開發(fā)者還是應該意識到其影響。
CompositeByteBuf API
CompositeByteBuf 提供了大量的附加功能超出了它所繼承的 ByteBuf。請參閱的 Netty 的 Javadoc 文檔 API。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯系方式:
更多建議: