Netty的字节容器ByteBuffer使用过于复杂,使用ByteBuf替代。

5.1 ByteBuf的API

详见 abstract class ByteBuf 和 interface ByteBufHolder.

5.2

网络通信涉及到字节序列的移动,所以高效易用的数据结构是很重要的。Netty的ByteBuf满足并超越了这些需求。

5.2.1 工作原理

ByteBuf维护了两个不同的索引,一个用于读取,一个用于写入。在名称以read或者write开头的ByteBuf方法,将会推进其对应的索引,而名称以set或get开头的操作则不会。

5.2.2 ByteBuf的使用模式

第一种模式 堆缓冲区

此模式将数据存储在JVM的堆内存中,这种模式被称为支撑数组。她能在没有使用池化的情况下提供快速的分配和释放。

第二种模式 直接缓冲区

直接缓冲区中的内容将驻留在常规的,会被垃圾回收的堆之外。如果你的数据包含在一个堆上分配的缓冲区中,那么事实上,在通过套接字发送之前,JVM将会在内部把你的缓冲区复制到一个直接缓冲区中。

第三种模式 复合缓冲区

复合缓冲区为多个ByteBuf提供了一个聚合视图。Netty通过ByteBuf的子类CompositeByByteBuf实现了这个模式。提供了一个将多个缓冲区表示为单个合并缓冲区的虚拟表示。

复合缓冲区的构造
使用netty的复合缓冲区模式

5.3 字节级操作

5.3.1 随机访问索引

第一个字节的索引是0.最后一个自己的索引是capacity()-1

5.3.2 顺序访问索引

ByteBuf的会被其read索引和write分为三部分。如下图。

在这里插入图片描述

5.3.3 可丢弃字节

如如上图,可丢弃的字节,包含了已经被读过的字节。通过discardReadBytes()方法,可以丢弃他们并回收空间。但不建议频繁调用这个防范。

5.3.4 可读字节

这个部分,存储了实际数据。通过readByte()进行读取。并移动read索引。

5.3.5 可写字节

指一个拥有未定义内容的,写入就绪的内存区域。

5.3.6 索引管理

netty可以通过markReaderIndex(),markWriteIndex(),resetReaderIndex(),resetWriterIndex()来操作索引。
也可以通过readerIndex(index),writerIndex(index)来将索引移动到指定位置。clear(),将ReaderIndex和WriterIndex置为0,它只是重置索引,并不会复制任何内存。

5.3.7 查找操作

indexOf() ,比较简单,,
indexOf(ByteBufProcessor),这时需要自己实现其方法process,这个方法用于检查输入的值是否是正在查找的值。
netty还定义了一些简答的查找操作,比如,包含以null结尾的内容可用buffer.forEachByte(ByteBufProcess.FIDN_NULL)

5.3.8 派生缓冲区

为ByteBuf提供了以专门的方式来呈现其内容的视图。有如下方法可以创建派生缓冲区。

  • duplicate()
  • slice()
  • slice(int,int)
  • Upooled,unmodifiableBuffer()
  • order(ByteOrder)
  • readSlice(int)

这些方法都将会返回一个新的ByteBuf实例,都会具有自己的读索引,写索引,标记索引。

5.3.9 读写操作

  • get*(),set*(),从给定的索引开始,并且保持索引不变
  • read*(),write*(). 从给定的索引开始,并且会根据已经访问的字节数对索引进行调整。

5.3.10 其他方法

名称描述
isReadable()如果至少有一个字节可供读取
isWritable()如果至少有一个字段可写入
readableBytes()返回可供读取的字节数
writablebytes()返回可被写入的字节数
capacity()返回ByteBuf 可容纳的字节
maxCapacity()返回ByteBuf可以容纳的最大字节数
hasArray()如果ByteBuf由一个字节数据支撑,返回true
array()如果ByteBuf由一个字节数据支撑则返回该数据,否则抛UnsupportedOperationException

5.4 ByteBufHolder 接口

ByteBufHolder为Netty提供了高级特性,比如缓冲区池化。常用操作如下:

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

5.5 ByteBuf分配

介绍管理ByteBuf实例的不同方式。

5.5.1 ByteBufAllocator接口

Netty通过接口ByteBufAllocator实现了ByteBuf的池化,可用来分配我们所描述的热议类型的ByteBuf实例。
常用APi:

名称描述
buffer()返回一个基于堆或者直接内存存储的ByteBuf
heapBuffer返回一个基于堆内存存储的ByteBuf
directBuffer返回一个基于直接内存存储的ByteBuf
compositeBuffer返回一个可以通过添加最大到指定书目的基于堆的或者基于直接内存存储的缓冲区来扩展的符合缓冲区

可以通过Channel(每个都可以有一个不同的ByteBufAllocator 实例)或者绑定到ChannelHandler 的ChannelHandlerContext 获取一个到ByteBufAllocator 的引用

5.5.2 Unpooled缓冲区

提供了静态的辅助方法来创建未池化的ByteBuf实例。有如下API:

名称描述
buffer返回一个未池化的基于堆内存存储的ByteBuf
directBufferfa返回一个未池化的基于直接内存存储的ByteBuf
wrappedBuffer()返回一个包装了给定数据的ByteBuf
copiedBuffer()返回了一个复制了给定数据的ByteBuf

5.5.3 ByteBufUtil类

提供了用于操作ByteBuf的静态辅助方法。
hexdump(): 以十六进制的表示形式打印ByteBuf的内容。

5.5.6 引用计数

引用计数是一种通过在某个对象所持有的资源不再被其他对象应用时释放该对象所持有的资源来优化内存使用和性能的技术。

最后

如果你觉得写的还不错,就关注下公众号呗,关注后,有点小礼物回赠给你。
你可以获得5000+电子书,java,springCloud,adroid,python等各种视频教程,IT类经典书籍,各种软件的安装及破解教程。
希望一块学习,一块进步!
在这里插入图片描述

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐