Netty ByteBuf梳理

我们知道,网络数据的基本单位总是字节。Java NIO提供了ByteBuffer作为它的字节容器,但是这个类使用起来过于复杂,而且也有些繁琐。
Netty的ByteBuffer替代品是ByteBuf,一个强大的实现,既解决了JDK API的局限性,又为网络应用程序的开发者提供了更好的API。

ByteBuf的API

Netty的数据处理API通过两个组件暴露——abstract class ByteBuf和interface ByteBufHolder。
下面是一些ByteBuf API的优点:

  • 它可以被用户自定义的缓冲区类型扩展;
  • 通过内置的复合缓冲区类型实现了透明的零拷贝;
  • 容量可以按需增长(类似于JDK的StringBuilder);
  • 在读和写这两种模式之间切换不需要调用ByteBuffer的flip()方法;
  • 读和写使用了不同的索引;
  • 支持方法的链式调用;
  • 支持引用计数;
  • 支持池化。
    其他可以用于管理ByteBuffer实例的分配,以及执行各种针对于数据容器本身和它所持有的数据的操作。

因为所有的网络通信都涉及字节序列的移动,所以高效易用的数据结构明显是必不可少的。Nety的ByteBuf实现满足并超越了这些需求。
ByteBuf维护了两个不同的索引:一个用于读取,一个用于写入。当你从ByteBuf读取时,它的readIndex将会被递增已经被读取的字节数。同样的,当你写入ByteBuf时,它的writeIndex也会被递增。
要了解这些索引两两之间的关系,如果打算读取字节直到radIndex达到writeIndex同样的值,你将会到达“可以读取的”数据的末尾。如果试图读取超过改点的数据将会触发一个IndexOutOfBoundsException。
名称为read或者write开头的ByteBuf方法,将会推进其对应的索引,而名称以ste或get开头的操作则不会。后面的这些方法将在作为一个参数传入的一个相对索引上执行操作。

ByteBufHolder接口

我们经常发现,除了实际的数据负载之外,我们还需要存储各种属性值。HTTP响应便是一个很好的例子,除了表示为字节的内容,还包括状态码、cookie等。
为了处理这种常见的用例,Netty提供了ByteBufHolder。ByteBufHolder也为Netty的高级特性提供了支持,入缓冲区池化,其中可以从池中借用ByteBuf,并且在需要时自动释放。
ByteBufHolder只有几种用于访问底层数据和引用计数的方法。

名称 描述
content() 返回由这个ByteBufHolder所持有的ByteBuf
copy() 返回这个ByteBufHolder得一个深拷贝,包括一个其所包含的ByteBuf的非共享拷贝
duplicate() 返回这个ByteBufHolder的以个浅拷贝,包括一个其所包含的ByteBuf的共享拷贝

如果想要实现一个将其有效负载存储在ByteBuf中的消息对象,那么ByteBufHolder将是个不错的选择。

ByteBuf分配

  • 按需分配:ByteBufAllocator接口
    为了降低分配和释放内存的开销,Netty通过interface ByteBufAllocator实现了(ByteBuf的)池化,它可以用来分配我们所描述过的任意类型的ByteBuf实例。使用池化是应用程序的决定,其并不会以任何方式改变ByteBuf API(的语义)。
    可以通过Channel(每一个可以有一个不同的ByteBufAllocator的实例)或者绑定到ChannelHandler的ChannelHnadlerContext获取一个到ByteBufAlocator的引用。
Channel channel = ... ;
ByteBufAllocator allocator = channel.alloc();
...
ChannelHandlerContext ctx = ... ;
ByteBufAllocator allocator2 = ctx.alloc();
...

  • Unpooled缓冲区
    可能某些情况下,你未能获取一个到ByteBufAllocator的引用。对于这种情况,Netty提供了一个简单地称为Unpooled的工具类,它提供了静态的辅助方法来创建未池化的ByteBuf实例。
原文地址:https://www.cnblogs.com/ioveNature/p/7943275.html