Netty 4.0的源碼結構與之前的3.X版本發生了較大的變化,以下是Netty 4.0源碼的層次結構
netty/
common/ - utility and logging
buffer/ - buffer API
transport/ - channel API and its core implementations
handler/ - channel handlers
codec/ - codec framework
codec-http/ - HTTP, Web Sockets, SPDY, and RTSP codec
example/ - examples
all/ - generates an all-in-one JAR
tarball/ - generates a tarball distribution
在接下來的源碼分析中,筆者打算對每個包實現的功能做詳細的分析(除了example包,all包和tarball包)。在這篇文章中,筆者將對buffer包進行分析。關于ByteBuf的readIndex,writeIndex和capacity可以閱讀之前的另外一篇文章《Netty 4.0 源碼分析(四):ByteBuf》。
Netty 4.0是一個異步NIO的消息通信框架,在分布式環境下,服務器之間的消息傳輸是基于I/O流的,在流傳輸中,字節是最小的傳輸單位,每個I/O流可以看做是對字節數組的操作。Buffer包中的ByteBuf實際上就是一個字節數組。
大端(Big Endian)和小段(Little Endian)
在開始討論buffer包之前,有必要了解一下大端(Big Endian)和小段(Little Endian)的區別。大端(Big Edian)和小端(Little Endian)是內存中數據儲存的字節序。不同體系的CPU在內存中的數據存儲往往存在著差異。例如,Intel的x86系列處理器將低序字節存儲在起始地址,而一些RISC架構的處理器,如IBM的370主機使用的PowerPC或Motorola公司生產的CPU,都將高序字節存儲在起始位置。這兩種不同的存儲方式被稱為Little Endian和Big Endian。
在Java中,Big Endian, Little Endian跟多字節類型的數據有關,比如int,short,long型,而對單字節數據byte卻沒有影響。BIG-ENDIAN就是低位字節排放在內存的高端,高位字節排放在內存的低端。而LITTLE-ENDIAN正好相反。
如果網絡上全部是PowerPC,SPARC和Motorola CPU的主機那么不會出現任何問題,但由于實際存在大量的IA架構的CPU,所以經常出現數據傳輸錯誤。
所有網絡協議都是采用Big Endian的方式來傳輸數據的。所以有時我們也會把Big Endian方式稱之為網絡字節序。當兩臺采用不同字節序的主機通信時,在發送數據之前都必須經過字節序的轉換成為網絡字節序后再進行傳輸。
在Netty 4.0的,默認的字節序是Big Endian(網絡字節序),在io.netty.buffer.Unpooled類中,定義了兩個ByteOrder類型的靜態變量
/**
* Big endian byte order.
*/
public static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN;
/**
* Little endian byte order.
*/
public static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN;
如果要改變改變字節序,可以調用io.netty.buffer.ByteBuf接口的order(ByteOrder endianness)方法。調用order方法,可以返回當前ByteBuf對象的字節序。
/**
* Returns the endianness of this buffer.
*/
ByteOrder order();
/**
* Returns a buffer with the specified endianness which shares the whole region,
* indexes, and marks of this buffer. Modifying the content, the indexes, or the marks of the
* returned buffer or this buffer affects each other's content, indexes, and marks. If the
* specified endianness is identical to this buffer's byte order, this method can
* return {@code this}. This method does not modify readerIndex or writerIndex of this buffer.
*/
ByteBuf order(ByteOrder endianness);
Channel和ByteBuf的理解
在Netty中,Channel是負責數據讀寫的對象,類似于java舊的I/O中stream。Channel是雙向的,既可以write,也可以read。在NIO中,用戶不能直接從Channel中讀寫數據,而是應該通過ByteBuf來進行讀寫操作,然后通過ByteBuf讀寫數據到Channel中。可以想象一個伐木場,Channel就是某個含有大量需要砍伐的樹木(數據)的采伐區,要想取得這些樹木(數據),就需要一輛卡車來運輸這些樹木(數據),這里的卡車就是ByteBuf(緩沖器),當卡車(ByteBuf)滿載而歸的時候,我們再從卡車中獲得樹木(數據)。
Netty 4.0中的buffer包
Netty 4.0中的io.netty.buffer包,總共定義了七個接口,十五個類,一個Enums類型。下圖是他們之間的關系

Io.netty.buffer包中的關系
Unpooled是個幫助類,是一個final class,并且它的構造器也是私有的,這意味的無法被別的類繼承,也無法通過new運算符來創建一個Unpooled對象。Unpool類的目的就是用于創建ByteBuf對象。
/**
* Creates a new big-endian Java heap buffer with the specified
* {@code capacity}. The new buffer's {@code readerIndex} and
* {@code writerIndex} are {@code 0}.
*/
public static ByteBuf buffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return EMPTY_BUFFER;
}
return new HeapByteBuf(initialCapacity, maxCapacity);
}
/**
* Creates a new big-endian direct buffer with the specified
* {@code capacity}. The new buffer's {@code readerIndex} and
* {@code writerIndex} are {@code 0}.
*/
public static ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
if (initialCapacity == 0 && maxCapacity == 0) {
return EMPTY_BUFFER;
}
return new DirectByteBuf(initialCapacity, maxCapacity);
}
/**
* Creates a new big-endian buffer which wraps the sub-region of the
* specified {@code array}. A modification on the specified array's
* content will be visible to the returned buffer.
*/
public static ByteBuf wrappedBuffer(byte[] array, int offset, int length) {
if (length == 0) {
return EMPTY_BUFFER;
}
if (offset == 0 && length == array.length) {
return wrappedBuffer(array);
}
return new SlicedByteBuf(wrappedBuffer(array), offset, length);
}
/**
* Returns a new big-endian composite buffer with no components.
*/
public static CompositeByteBuf compositeBuffer(int maxNumComponents) {
return new DefaultCompositeByteBuf(maxNumComponents);
}
/**
* Creates a read-only buffer which disallows any modification operations
* on the specified {@code buffer}. The new buffer has the same
* {@code readerIndex} and {@code writerIndex} with the specified
* {@code buffer}.
*/
public static ByteBuf unmodifiableBuffer(ByteBuf buffer) {
if (buffer instanceof ReadOnlyByteBuf) {
buffer = ((ReadOnlyByteBuf) buffer).unwrap();
}
return new ReadOnlyByteBuf(buffer);
}
通過Unpooled創建ByteBuf對象:
ByteBuf heapBuffer = Unpooled.buffer(128);
ByteBuf directBuffer = Unpooled.directBuffer(256);
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(new byte[128], new byte[256]);
ByteBuf的類型
在Netty 4.0中,ByteBuf有以下幾種類型,分別是HeapByteBuf,WrappedByteBuf,DirectByteBuf,CompositeByteBuf。 HeapByteBuf在Unpooled類中是默認的ByteBuf類型,通過Unpooled.buffer()取得。某人的緩沖器大小是256字節。
WrappedByteBuf用于包裝一個字節數組或者一個ByteBuf,通過Unpooled.wrappedBuffer(byte[] array)或者Unpooled.wrappedBuffer(ByteBuf bytebuf)取得。
DirectByteBuf是NIO的基本緩存器。
CompositeByteBuf是一個組合緩沖器,將多個ByteBuf對象組合在同一個緩沖器中。
具體看如下代碼:
public class ByteBufTypeDemo {
public static void main(String[] args){
byte[] byteArrayA = {1, 2};
byte[] byteArrayB = {3, 4};
ByteBuf heapBuffer = Unpooled.buffer();
System.out.println("/***********Heap ByteBuf***************/");
System.out.println("Default Byte Order: " + heapBuffer.order());
System.out.println("Default Heap Buffer Capacity: " + heapBuffer.capacity());
System.out.println();
System.out.println();
ByteBuf wrappedBufferA = Unpooled.wrappedBuffer(byteArrayA);
System.out.println("/***********Wrapped ByteBuf***************/");
for(int i = 0; i < wrappedBufferA.writerIndex(); i++){
System.out.println(wrappedBufferA.getByte(i));
}
System.out.println();
System.out.println();
ByteBuf wrappedBufferB = Unpooled.wrappedBuffer(byteArrayB);
ByteBuf compositeByteBuf = Unpooled.compositeBuffer().addComponent(wrappedBufferA).addComponent(wrappedBufferB);
Iterator<ByteBuf> compositeIterator = ((CompositeByteBuf)compositeByteBuf).iterator();
System.out.println("/***********Composite ByteBuf***************/");
while(compositeIterator.hasNext()){
ByteBuf tempBuf = compositeIterator.next();
for(int i = 0; i < 2;i++){
System.out.println(tempBuf.getByte(i));
}
}
System.out.println();
System.out.println();
System.out.println("/***********Direct ByteBuf***************/");
ByteBuf directByteBuf = (DirectByteBuf)Unpooled.directBuffer();
System.out.println("Has NIO Buffer? " + directByteBuf.hasNioBuffer());
System.out.println();
System.out.println();
System.out.println("/*****************End*********************/");
}
}
參考引用:http://baike.baidu.com/view/2368412.htm
備注:因為筆者開始寫Netty源碼分析的時候,Netty 4.0還是處于Alpha階段,之后的API可能還會有改動,筆者將會及時更改。使用開源已經有好幾年的時間了,一直沒有時間和精力來具體研究某個開源項目的具體實現,這次是第一次寫開源項目的源碼分析,如果文中有錯誤的地方,歡迎讀者可以留言指出。對于轉載的讀者,請注明文章的出處。
希望和廣大的開發者/開源愛好者進行交流,歡迎大家的留言和討論。
-----------------------------------------------------
Silence, the way to avoid many problems;
Smile, the way to solve many problems;