ByteBuf工作原理

ByteBuf依然是个Byte数组的缓冲区,它的基本功能与JDK的ByteBuffer一致。

功能分析

ByteBuffer完全可以满足NIO编程的需要,但是由于NIO编程的复杂性,ByteBuffer也有其局限性,它的主要缺点如下。

  • ByteBuffer长度固定,一旦分配完成,它的容量不能动态扩展和收缩,当需要编码的POJO对象大于ByteBuffer的容量时,会发生索引越界异常;
  • ByteBuffer只有一个标识位置的指针position,读写的时候需要手工调用flip()和rewind()等,使用者必须小心谨慎地处理这些API,否则很容易导致程序处理失败;
  • ByteBuffer的API功能有限,一些高级和实用的特性它不支持,需要使用者自己编程实现。

为弥补这些不足,Netty提供了自己的ByteBuffer实现——ByteBuf。ByteBuf依然是个Byte数组的缓冲区,它的基本功能应该与JDK的ByteBuffer一致,提供以下几类基本功能:

  1. 7种Java基础类型、byte数组、ByteBuffer等的读写;
  2. 缓冲区自身的copy和slice等;
  3. 设置网络字节序;
  4. 构造缓冲区实例;
  5. 操作位置指针等方法。

由于JDK的ByteBuffer已经提供了这些基础能力的实现,因此,Netty ByteBuf的实现可以有两种策略。

  • 参考JDK ByteBuffer的实现,增加额外的功能,解决原ByteBuffer的缺点。
  • 聚合JDK ByteBuffer,通过Facade模式对其进行包装,可以减少自身的代码量,减低实现的成本。

缓冲区工作过程

JDK ByteBuffer由于只有一个位置指针用于处理读写操作,因此每次进行读写的时候都需要额外调用filp()和clear()等方法,否则功能将出错,他的典型用法如下。

1
2
3
4
5
6
7
ByteBuffer buffer=ByteBuffer.allocate(88);
String value ="Netty 权威指南";
buffer.put(value.getByte());
buffer.filp();
byte[] vArray=new byte[buffer.remaining];
buffer.get(vArray);
String decodeValue=new String(vArray);

我们看下调用filp()操作前后的对比。



图1 ByteBuffer filp()操作之前

如图2 所示,如果不做filp操作,读取到的将是position到capacity之间的错误内容。
当执行filp()操作之后,他的limit被设置为position,position设置为0,capacity不变。由于读取的内容是从position到limit之间,因此,他能够正确地读到之前写入缓冲区的内容。如图3所示



图2 ByteBuffer filp()操作之后

ByteBuf通过两个位置指针来协助缓冲区的读写操作,读操作使用readerIndex,写操作使用writeIndex。

readerIndex和writeIndex的取值一开始都是0,随着数据的写入writeIndex会增加,读取数据会使readIndex增加,但是它不会超过writeIndex。在读取之后,0~readerIndex被视为discard的,调用discardReadBytes方法,可以释放这部分空间,它的作用类似ByteBuffer的compact方法。ReaderIndex与writeIndex之间的数据是可读取的,等价于ByteBuffer position 和limit之间的数据。writeIndex与capacity之间的空间是可写的,等价于ByteBuffer limit和capacity之间的可用空间**
由于写操作不修改readerIndex指针,读操作不修改writeIndex指针,因此读写之间不再需要调整位置指针,这极大低简化了缓冲区的读写操作,避免了由于遗漏或者,不熟悉filp()操作导致的功能异常。
初始分配的ByteBuf如图4所示。



图3 初始分配的ByteBuf

写入N个字节之后ByteBuf如图5所示。



图4 写入N个字节后的ByteBuf

读取M(< N)个字节之后的ByteBuf如图6所示。



图5 读取M个字节后的ByteBuf

调用disacardReadBytes操作之后的ByteBuf如图7所示。



图6 discardReadByte操作之后的ByteBuf

调用clear操作之后的ByteBuf如图8所示。



图7 clear操作之后的ByteBuf

Adhere to the original technology to share, your support will encourage me to continue to create!