NIO的Buffer之前介绍过了,这边来看看Netty的ByteBuf。
ByteBuf
ByteBuf维护了两个不同的索引:一个用于读取,一个用于写入,分别对应readerIndex和writerIndex。每次读的时候,readerIndex加1,写的时候writerIndex加1。在使用时,即可以使用堆缓冲区,也可以使用直接缓冲区,还可以使用复合缓冲区。
ByteBuf的内部分段如下,小于readerIndex的说明已经读取完了,为可丢弃字节,大于readerIndex小于writerIndex的为可读字节,大于writerIndex小于capacity的为可写字节。
为了下面例子方便,先贴一个初始化代码,定义了一个初始容量为4,最大容量为8的ByteBuf。如果扩容的话,至少64,8太小会报错,这边就不进行扩容操作。
public static ByteBuf init() {
ByteBuf byteBuf = Unpooled.buffer(4, 8);
System.out.println("----------init----------");
System.out.println(byteBuf.toString());
System.out.println("init:" + byteBuf.toString(CharsetUtil.UTF_8));
return byteBuf;
}
write和read
public static void main(String[] args) {
ByteBuf byteBuf = init();
writeAndRead(byteBuf);
}
public static void writeAndRead(ByteBuf byteBuf) {
System.out.println("----------write----------");
byteBuf.writeBytes("ab".getBytes());
System.out.println(byteBuf.toString());
System.out.println("write:" + byteBuf.toString(CharsetUtil.UTF_8));
byteBuf.writeBytes("cd".getBytes());
System.out.println(byteBuf.toString());
System.out.println("write:" + byteBuf.toString(CharsetUtil.UTF_8));
System.out.println("----------read----------");
byteBuf.readByte();
System.out.println(byteBuf.toString());
System.out.println("read:" + byteBuf.toString(CharsetUtil.UTF_8));
}
运行结果如下:
----------init----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 4/8)
init:
----------write----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 4/8)
write:ab
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 4, cap: 4/8)
write:abcd
----------read----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 1, widx: 4, cap: 4/8)
read:bcd
可以看出,初始化的时候,读和写的索引都是0,当写入ab的时候,写的索引为2,写入cd的时候,写的索引为4。读取第一个字节的时候,读的索引加1。
isWritable和isReadable
isWritable和isReadable是判断是否有字节允许可写可读。
public static void main(String[] args) {
ByteBuf byteBuf = init();
writeAndRead2(byteBuf);
}
public static void writeAndRead2(ByteBuf byteBuf) {
while (byteBuf.isWritable()) {
byteBuf.writeBytes("aa".getBytes());
System.out.println(byteBuf.toString());
System.out.println("write:" + byteBuf.toString(CharsetUtil.UTF_8));
}
while ((byteBuf.isReadable())){
byteBuf.readByte();
System.out.println(byteBuf.toString());
System.out.println("read:" + byteBuf.toString(CharsetUtil.UTF_8));
}
}
运行结果如下:
----------init----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 4/8)
init:
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 4/8)
write:aa
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 4, cap: 4/8)
write:aaaa
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 1, widx: 4, cap: 4/8)
read:aaa
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 2, widx: 4, cap: 4/8)
read:aa
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 3, widx: 4, cap: 4/8)
read:a
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 4, widx: 4, cap: 4/8)
read:
get 和 set
public static void main(String[] args) {
ByteBuf byteBuf = init();
getAndset(byteBuf);
}
public static void getAndset(ByteBuf byteBuf) {
System.out.println("----------write----------");
byteBuf.writeBytes("ab".getBytes());
System.out.println(byteBuf.toString());
System.out.println("set:" + byteBuf.toString(CharsetUtil.UTF_8));
System.out.println("----------set----------");
byteBuf.setByte(0, (byte) 'A');
System.out.println(byteBuf.toString());
System.out.println("set:" + byteBuf.toString(CharsetUtil.UTF_8));
System.out.println("----------get----------");
byte b = byteBuf.getByte(0);
System.out.println((char) b);
System.out.println(byteBuf.toString());
System.out.println("get:" + byteBuf.toString(CharsetUtil.UTF_8));
}
运行结果如下:
----------init----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 4/8)
init:
----------write----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 4/8)
set:ab
----------set----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 4/8)
set:Ab
----------get----------
A
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 4/8)
get:Ab
可以看出,get和set方法,并不会对索引有影响。
discardReadBytes
用于丢弃字节并回收空间。
public static void main(String[] args) {
ByteBuf byteBuf = init();
discardReadBytes(byteBuf);
}
public static void discardReadBytes(ByteBuf byteBuf) {
System.out.println("----------write----------");
byteBuf.writeBytes("ab".getBytes());
System.out.println(byteBuf.toString());
System.out.println("----------read----------");
byteBuf.readByte();
System.out.println(byteBuf.toString());
System.out.println("read:" + byteBuf.toString(CharsetUtil.UTF_8));
System.out.println("----------discardReadBytes----------");
byteBuf.discardReadBytes();
System.out.println(byteBuf.toString());
System.out.println("discardReadBytes:" + byteBuf.toString(CharsetUtil.UTF_8));
}
运行结果如下:
----------init----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 4/8)
init:
----------write----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 2, cap: 4/8)
----------read----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 1, widx: 2, cap: 4/8)
read:b
----------discardReadBytes----------
UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 1, cap: 4/8)
discardReadBytes:b
在调用discardReadBytes方法前,读的索引是1,写的索引是2,可丢弃的字节就是0-1之间,调用discardReadBytes方法后,读的索引是0,写的索引是1。
虽然discardReadBytes可以回收空间,但是这操作极有可能导致内存复制,因为需要把读索引后面的字节复制到缓冲区的开始位置。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。