1--ByteBuf的API的优点
》可以被用户自定义的缓冲区类型扩展
》通过内置的复合缓冲区类型实现了透明的零拷贝
》容量可以按需增长
》在读和写这两种模式间切换不需要调用ByteBuffer的flip()方法
》读和写分别使用了readerIndex和writerIndex两个索引
》支持方法的链式调用
》支持引用计数
》支持池化技术
2--ByteBuf的使用模式
(a)堆缓冲区
(b)直接缓冲区
(c)复合缓冲区
============================堆缓冲区=================
最常用的ByteBuf模式是将数据存储在JVM的堆空间,这种模式能够在没有使用池化的情况下提供快速的分配和释放,如下代码。
ByteBuf heapBuf=...;
if(heapBuf.hasArray()){//检查ByteBuf缓冲是否有一个内部数组---若返回false则触发不支持操作异常
byte[] array=heapBuf.array();
int offset=heapBuf.arrayOffset()+heapBuf.readerIndex();//计算第一个字节的偏移量
int len=heapBuf.readableBytes();
handleArray(array,offset,len);//自定义的方法调用数组、偏移量、长度参数来处理
}
======================直接缓冲区=================
1》直接缓冲区的内容将驻留在常规的会被垃圾回收的堆之外。直接缓冲区对于网络数据传输是理想的选择。
如果你的数据包含在一个在堆上分配的缓冲区中,实际上在通过套接字发送它之前,JVM将会在内部把你的
缓冲区复制到一个直接缓冲区。
2》直接缓冲区的主要缺点:相对于堆缓冲区而言,直接缓冲的的分配释放比较昂贵。如果你正在处理遗留代码
可能会遇到一个问题,由于数据不在堆上,所以需要进行复制,如下代码。
ByteBuf directBuf=...;
if(!directBuf.hasArray()){//不是堆缓冲,则是一个直接缓冲
int len=directBuf.readableBytes();//获取可读字节数
byte[] arr=new byte[len];
directBuf.getBytes(directBuf.readerIndex(),arr);//将字节复制到数组arr
handArr(arr,0,len);//自己的方法
}
================复合缓冲区======
复合缓冲区为多个ByteBuf提供一个聚合视图,可以根据需要添加或删除ByteBuf实例。
Netty通过一个ByteBuf子类CompositeByteBuf(可能同时包含直接内存分配和非直接内存分配)实现了复合缓冲区,
它提供了一个将多个缓冲区表示为单个合并缓冲区的虚拟表示。
CompositeByteBuf cbuf=Unpooled.compositeBuffer();
ByteBuf buf1=...;
ByteBuf buf2=...;
cbuf.addComponents(buf1,buf2);//将两个缓冲组件添加到复合缓冲区
cbuf.removeComponents(0);//删除位于第一个位置的缓冲
for(ByteBuf buf:cbuf){
System.out.println(buf.toString());
}
==============字节级别的操作==========
1》随机访问索引
ByteBuf buf=...;
for(int i=0;i<buf.capacity();i++){
byte b=buf.getByte(i);
System.out.println((char)b);
}
注:使用那些需要一个索引值参数的方法之一来访问数据既不会改变readerIndex也不会改变writerIndex.
通过readerIndex(index)或者writerInder(index)可以改变索引值
2》顺序访问索引