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;