Netty学习~入门

Netty 中的 ByteBuf 类似于 Java Nio 中的 ByteBuffer 类,是用于保存向管道中 写入/读取 数据的缓冲区,也可以称它为数据容器。

public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf> 
复制代码
首先 ByteBuf 是一个抽象类,它可以被继承,用户可以用它根据自己的需求扩展 它可以自动扩容,而 ByteBuffer 的容量在初始化后就固定了,不能更改 从上面的代码片段可知它实现了 ReferenceCount 和 Comparable 接口,说明它支持引用计数并且支持比较操作 支持池化 具有两个下标分别是 readerIndex 和 writerIndex(如图1),操作方便,而 ByteBuffer 只有一个 position 下标,读/写操作之间需要转换 内部的复合缓冲区可以实现透明的零拷贝 支持链式调用
图 1

ByteBuf 有三种使用模式:

  • 堆缓冲区:这种模式将缓冲区数据(ByteBuf 中的数据)存储在 Java 堆中,并且带有一个支撑数组,可以通过获取数组来获取缓冲区中的数据,可以通过 Unpooled.buffer() 或 Unpooled.copiedBuffer() 方法创建,在访问堆缓冲区数据的时候先用 hasArray() 判断是否具有支撑数组,然后使用 array() 方法获取 byte 数组,这个数组就是缓冲区的数据
  • 直接缓冲区:将数据存储在 Java 堆外的内存区域,这片区域是可以被 JVM 管理的直接缓冲区,没有支撑数组,可以通过 Unpooled.directBuffer() 创建,这种缓冲区的内容需要进行一次赋值才能够得到,因为数据是存储在 JVM 之外的,所有需要先用 getBytes(readerIndex(), byte[]) 方法将直接缓冲区的数据复制到 byte 数组中。但是这种缓冲区的好处是在网络传输时如果我们的数据在堆缓冲区中,那么在传输时需要先将 JVM 中的数据赋值到直接缓冲区才能够发送,直接缓冲区的数据则可以直接发送。这种缓冲区因为不再 JVM 中的缘故,它的释放和分配代价昂贵。
  • 复合缓冲区:使用 CompositeByteBuf 类实现,可以将多个 ByteBuf 聚合成一个视图,也就是说 CompositeByteBuf 中可以存储多个 ByteBuf 实例,这样有利于缓冲区重用,避免了一些不必要的复制。可以通过 Unpooled.compositeBuffer() 创建。

补充:符合缓冲区中不仅能够包装其他缓冲区,还能存储自己的数据。

ByteBuf 基本用法

篇幅原因这里说一说最基本的一些方法,其他用法请查看 API 学习。 缓冲区最基本的操作首先就是 存入/读取 数据,ByteBuf 的 读/存 数据主要分两种,一种是有移动下标的,一种是不移动下标的,这里的下标就是上面 图1 中的 readIndex 和 writeIndex 这两个下标。一般以 read 和 write 开头的方法都会移动下标,而以 get 和 set 开头的方法都不会移动下标。
ByteBuf.readBytes(byte[] bts) 将当前缓冲区的数据复制到 bts 数组中 当前缓冲区的 readIndex 增加
ByteBuf.readBytes(ByteBuf btf) 将当前缓冲区的数据写入到 btf 缓冲区中 当前缓冲区的 readIndex 增加,btf 的 writeIndex 增加
ByteBuf.writeBytes(byte[] bts) 将 bts 数组中的数据写入到当前缓冲区中 当前缓冲区的 writeIndex 增加
ByteBuf.writeBuf(ByteBuf btf) 将 btf 缓冲区中的数据写入到当前缓冲区中 当前缓冲区的 writeIndex 增加,btf 的 readIndex 增加
ByteBuf.getBytes(int index, byte[] bts) 将当前缓冲区的数据复制到 bts 中,从当前缓冲区的 index 下标位置开始 下标不移动
ByteBuf.getBytes(int index, ByteBuf btf) 将当前缓冲区的内容复制到 btf 中,从当前缓冲区的 index 下标位置开始
ByteBuf.setBytes(int index, byte[] bts) 将 bts 中的数据存储到当前缓冲区,从当前缓冲区的 index 下标位置开始
ByteBuf.setBytes(int index, BytsBuf btf) 将 btf 中的数据存储到当前缓冲区,从当前缓冲区的 index 下标位置开始

上面方法要注意越界操作会抛出 IndexOutOfBoundsException 异常。

注:在 ByteBuf.readBytes(ByteBuf btf) 方法中,要求将 btf 写满,要么当前缓冲区中的内容全部写完正好写满 btf,要么当前缓冲区内容没有全部写入 btf 中,但是 btf 已经满了,否则将抛出异常。

ByteBuf 也提供 writeIndex 和 readIndex 的 标记/重置 操作,通过 markWriterIndex()\markReaderIndex 和 resetWriterIndex()/resetReaderIndex() 实现。

ByteBuf.clear() 方法将两个下标重置到 0,但是不会清除缓冲区原有的内容;

ByteBuf.discardReadBytes() 方法将以读取数据清除,这样 readerIndex=0,而 writerIndex 向前移动,相比于 clear() 方法,这个方法产生了数据复制,速度更慢,建议在内存急缺的情况使用。

转载于:https://juejin.im/post/5cfe0e1551882506cf358171

猜你喜欢

转载自blog.csdn.net/weixin_33794672/article/details/93178462