【Netty】 ByteBuf的常用API总结

目录

一、ByteBuf介绍

二、ByteBuf创建

1.池化创建 ByteBufAllocator

2.Unpooled (非池化)创建ByteBuf

3.ByteBufUtil 操作ByteBuf

三、读取ByteBuf数据

1.get方法

2.read方法

3.set方法

4.write方法

5.索引管理 

 6.索引查找

 7.ByteBuf复制

 8.其他方法


本篇主要介绍ByteBuf的常用操作API,Netty性能的卓越表现离不开ByteBuf的巧妙设计,它提供了一系列的缓冲区读写方法,另外为了方便起见还特定义了ByteBufUtil,提供了比较丰富的操作ByteBuf方法。

一、ByteBuf介绍


为了提高性能,Netty重新设计了字节缓冲区ByteBuf,类似Java Nio的ByteBuffer,但工作方式略有区别,比后者更加灵活、高效。

ByteBuf有几个重要属性:

capacity:容量;
0:缓冲区开始位置;
readIndex:下一个读位置;
writeIndex:下一个写位置;
一个ByteBuf对象即可像byte数组一样工作,又可以像IO字节流一样工作。当前的可读数据区是[readIndex,writeIndex);可写区是[writeIndex,capacity);而[0,readIndex)区间的字节是可废弃数据(Discardable),如下图所示:

+-------------------+------------------+------------------+  
| discardable bytes |  readable bytes  |  writable bytes  |  
|                   |     (CONTENT)    |                  |  
+-------------------+------------------+------------------+  
|                   |                  |                  |  
0      <=      readerIndex   <=   writerIndex    <=    capacity

基本的操作包括

1.从ByteBuf中读取数据,从readerIndex开始向后读取需要的字节数,readerIndex随之改变;

2.向ByteBuf中写数据,从writeIndex开始向后写数据,同时writeIndex随之改变;

3.删除ByteBuf已读数据,从[0,readerIndex)为已读完的数据,为了节省空间需要释放内存,释放示意图如下:


 *  BEFORE discardReadBytes()
 *
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 *
 *
 *  AFTER discardReadBytes()
 *
 *      +------------------+--------------------------------------+
 *      |  readable bytes  |    writable bytes (got more space)   |
 *      +------------------+--------------------------------------+
 *      |                  |                                      |
 * readerIndex (0) <= writerIndex (decreased)        <=        capacity

4.清空ByteBuf数据,不需要清空数据,通过移动两个指针readerIndex和writeIndex,指向0即可。


 *  BEFORE clear()
 *
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 *
 *
 *  AFTER clear()
 *
 *      +---------------------------------------------------------+
 *      |             writable bytes (got more space)             |
 *      +---------------------------------------------------------+
 *      |                                                         |
 *      0 = readerIndex = writerIndex            <=            capacity

二、ByteBuf创建

1.池化创建 ByteBufAllocator

即PooledByteBufAllocator

获取ByteBufAllocator,通过以下两种方式获取

//方法1
Channel channel = ...;
ByteBufAllocator allocator = channel.alloc();  
//方法2
ChannelHandlerContext ctx = ...;
ByteBufAllocator allocator2 = ctx.alloc();  

ByteBufAllocator中创建byteBuf的方法如下

方法名称方法描述

buffer()

buffer(int)

buffer(int, int)

Return a ByteBuf with heap-based or direct data storage

heapBuffer()

heapBuffer(int)

heapBuffer(int, int)

Return a ByteBuf with heap-based storage.

directBuffer()

directBuffer(int)

directBuffer(int, int)

Return a ByteBuf with direct storage.

compositeBuffer()

compositeBuffer(int)

heapCompositeBuffer()

heapCompositeBuffer(int) directCompositeBuffer()

directCompositeBuffer(int) 
   

  Return a CompositeByteBuf that can be expanded by adding heapbased or direct buffers. 

ioBuffer()

Return a ByteBuf that will be used for I/O operations on a socket.

2.Unpooled (非池化)创建ByteBuf

即UnPooledByteBufAllocator

当未引用 ByteBufAllocator 时,上面的方法无法访问到 ByteBuf。对于这个用例 Netty 提供一个实用工具类称为 Unpooled,,它提供了静态辅助方法来创建非池化的 ByteBuf 实例,方法如下:

方法名称方法描述

buffer()

buffer(int)

buffer(int, int)

Returns an unpooled ByteBuf with heap-based storage

directBuffer()

directBuffer(int)

directBuffer(int, int)

Returns an unpooled ByteBuf with direct storage

wrappedBuffer()

Returns a ByteBuf, which wraps the given data.

copiedBuffer()

Returns a ByteBuf, which copies the given data

3.ByteBufUtil 操作ByteBuf

三、读取ByteBuf数据

 get类似数组操作,不会改变读索引readIndex,read会改变读索引readIndex。

1.get方法

方法名称方法描述

getBoolean(int)

返回当前索引的 Boolean 值

getByte(int)

getUnsignedByte(int)

返回当前索引的(无符号)字节

getMedium(int)

getUnsignedMedium(int)

返回当前索引的 (无符号) 24-bit 中间值

getInt(int)

getUnsignedInt(int)

返回当前索引的(无符号) 整型

getLong(int)

getUnsignedLong(int)

返回当前索引的 (无符号) Long 型

getShort(int)

getUnsignedShort(int)

返回当前索引的 (无符号) Short 型

getBytes(int, ...)

字节

2.read方法

方法名称方法描述

readBoolean() 

 返回当前索引的Boolean值,读索引加一

readByte() 

readUnsignedByte() 

返回当前索引的(无符号)字节,读索引加一

readMedium() 

readUnsignedMedium() 

返回当前索引的 (无符号) 24-bit 中间值,读索引加3

readInt() 

readUnsignedInt()

 返回当前索引的(无符号) 整型,读索引加4

readLong() 

readUnsignedLong() 

 返回当前索引的 (无符号) Long 型,读索引加8

readShort() 

readUnsignedShort() 

返回当前索引的 (无符号) Short 型,读索引加2

readBytes(int length)读取length字节数,并返回一个新创建的Buf对象,新buf的readIndex=0,writeIndex=length,源buf的readIndex+=length
readBytes(ByteBuf dst)将buf的可读字节写入dst,字节数=min(src.readableBytes,dst.writableBytes),src.readIndex增加,src.writeIndex增加
readBytes(ByteBuf dst, int length)同上,指定长度
readBytes(ByteBuf dst, int dstIndex, int length)同上,但不修改dst.writeIndex
readBytes(byte[] dst)数组版本,也有其他变体
readBytes(ByteBuffer dst)nio buffer版本
readBytes(OutputStream out, int length)ostream版本
readBytes(GatheringByteChannel out, int length)nio channel版本
readCharSequence(int length, Charset charset)字符串版本
readBytes(FileChannel out, long position, int length)文件Channel版本
skipBytes(int length)跳过一些可读字节,readIndex+=length

3.set方法

方法名称方法描述

setBoolean(int, boolean)

在指定的索引位置设置 Boolean 值

setByte(int, int)

在指定的索引位置设置 byte 值

setMedium(int, int)

在指定的索引位置设置 24-bit 中间 值

setInt(int, int)

在指定的索引位置设置 int 值

setLong(int, long)

在指定的索引位置设置 long 值

setShort(int, int)

在指定的索引位置设置 short 值

4.write方法

方法名称方法描述

writeBoolean(boolean)

在指定的索引位置设置 Boolean 值,写索引加一

writeByte(int)

在指定的索引位置设置 byte 值,写索引加一

writeMedium(int)

在指定的索引位置设置 24-bit 中间 值,写索引加3

writeInt(int)

在指定的索引位置设置 int 值,写索引加4

writeLong(long)

在指定的索引位置设置 long 值,写索引加8

writeShort(int)

在指定的索引位置设置 short 值,写索引加2

writeBytes(int,...)

 在当前索引写入一个Byte数组,写索引加数组长度

5.索引管理 

方法名称方法描述

markReaderIndex(),

 markWriterIndex()

标记读(写)索引

resetReaderIndex()

resetWriterIndex()

读(写)索引回到mark标记的索引值

readerIndex(int)

writerIndex(int) 

将读(写)索引设置到指定位置

clear()

可以同时设置 readerIndex 和 writerIndex 为 0。这不会清除内存中的内容

discardReadBytes抛弃已读字节,将[readerIndex, writeIndex)字节迁移到[0, readableBytes),修改readerIndex=0,writeIndex=readableBytes
discardSomeReadBytes抛弃部分已读字节以节省内存,具体数量由实现来决定,以达到最高效
ensureWritable(int minWritableBytes)按需扩展容量,如果writeIndex+minWritableBytes> maxCapacity,抛出IndexOutOfBoundsException
ensureWritable(int minWritableBytes, boolean force)    
 
功能同上,但不会抛出异常,参数force影响(writeIndex+minWritableBytes> maxCapacity)条件下的行为:force=true,扩充容量至maxCapacity;force=false,不做扩充。返回值只一个反映操作行为的状态码:=0,容量本来就满足,所以未扩充;=1,容量不足,但未扩充;=2,容量已扩充,满足需求;=3,容量以扩充至maxCapacity,但仍未满足需求。

 6.索引查找

方法名称方法描述
bytesBefore(int index, int length, byte value)查询value在buf出现的位置,仅限[index,index+length)区间内查找

for EachByte(ByteBufProcessor.FIND_NUL)

查找byte,返回byte的索引

 7.ByteBuf复制

方法名称方法描述
slice()返回源buf可读字节的一个切片,新buf和源buf共享byte内存,但readIndex,writeIndex互相独立,操作buf不会影响refCnt
duplicate()
retainedDuplicate()
制作buf的一个副本,底层共享byte内存,但readIndex,writeIndex互相独立,操作buf不会影响refCnt
slice(int index, int length)
retainedSlice(int index, int length)
slice变体
retainedSlice()相当于slice().retain()
copy()复制buf的可读字节区,新buf的readIndex=0,新buf和源buf互相独立
copy(int index, int length)新buf的readIndex=0, writeIndex=capacity=length

 8.其他方法

方法名称方法描述
unwrap()如果此对象是包装另一个ByteBuf对象生成的,返回后者,否则返回null
isDirect()是否该ByteBuf是一个直接内存缓冲区
isReadOnly()是否只读
asReadOnly()返回该ByteBuf的一个只读版本
readerIndex(int readerIndex)设置readerIndex,不能<0,或>writerIndex
writerIndex(int writerIndex)设置writerIndex,不能<readerIndex,或> capacity
setIndex(int readerIndex, int writerIndex)同时设置readerIndex, writerIndex
readableBytes()返回可以读的字节长度=writerIndex-readerIndex
isReadable()返回是否有字节可读=(writerIndex-readerIndex>0)
isReadable(size)返回是否有size字节可读=(writerIndex-readerIndex>size)
writableBytes()返回可以写的字节长度=capacity-writerIndex
maxWritableBytes()返回最大可以写的字节长度=maxCapacity-writerIndex

isWritable()

返回是否可以写==(capacity - writerIndex)>0

isWritable(int size)返回是否可以写字节长度size=(capacity - writerIndex)>size
clear()恢复到初始状态,相当于setIndex(0,0)

capacity()

返回byteBuf的容量

maxCapacity()

返回byteBuf可以有的最大容量

hasArray()

buf内部是否被一个byte array支撑

(heap buf才会为true)

array()

返回支撑的byte array,如果不支持,抛出UnsupportedOperationException
arrayOffset()返回buf的0位置,在byte数组中的位置
hasMemoryAddress()buf是否拥有一个指向底层内存的地址
memoryAddress()返回底层内存地址,如果不支持,抛出UnsupportedOperationException
isContiguous()buf是否由一整块内存支持

参考资料

ByteBuf的常用API总结

Netty详解之九:ByteBuf介绍

### Netty 常用 API 列表及其使用方法 #### 1. **Channel** `Channel` 是 Netty 中的一个核心接口,表示一个网络连接。通过 `Channel` 可以读取和写入数据[^1]。 - **主要功能**: 提供对底层 I/O 操作的抽象。 - **常见实现类**: - `SocketChannel`: 表示 TCP 客户端连接。 - `ServerSocketChannel`: 表示 TCP 服务端监听器。 ```java // 获取 Channel 配置选项 channel.config().setOption(ChannelOption.SO_BACKLOG, 128); ``` --- #### 2. **ChannelHandler** `ChannelHandler` 是用于处理各种事件(如读、写、异常等)的组件。它是 Netty 处理业务逻辑的主要入口[^2]。 - **分类**: - `ChannelInboundHandler`: 负责处理入站事件。 - `ChannelOutboundHandler`: 负责处理出站事件。 - **常用子类**: - `SimpleChannelInboundHandler<T>`: 自动释放资源并简化了消息接收流程。 - `ChannelInitializer<Channel>`: 初始化管道时添加其他处理器。 ```java public class MyHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { System.out.println("Received message: " + msg); } } ``` --- #### 3. **ChannelPipeline** `ChannelPipeline` 是一组按顺序排列的 `ChannelHandler` 实例集合。它负责管理这些处理器之间的交互[^4]。 - **作用**: 将不同的操作分配给特定的 `ChannelHandler` 来完成。 - **常用方法**: - `addLast(ChannelHandler handler)`:向管道末尾添加一个新的处理器。 - `remove(ChannelHandler handler)`:移除指定的处理器。 ```java pipeline.addLast(new LoggingHandler()); pipeline.addLast(new MyHandler()); ``` --- #### 4. **ChannelHandlerContext** `ChannelHandlerContext` 表示某个 `ChannelHandler` 在 `ChannelPipeline` 中的状态和上下文信息。 - **用途**: 提供访问当前 `ChannelHandler` 所属的 `Channel` 和 `ChannelPipeline` 的能力。 - **常用方法**: - `write(Object msg)`:将消息发送到下游。 - `fireChannelRead(Object msg)`:触发上游的读事件。 ```java ctx.writeAndFlush(msg); // 向下一个处理器传递消息 ``` --- #### 5. **EventLoopGroup** `EventLoopGroup` 是一组线程池,专门用来执行 I/O 操作的任务调度。 - **典型实现**: - `NioEventLoopGroup`: 基于 NIO 的多路复用机制。 - **配置实例**: ```java EventLoopGroup bossGroup = new NioEventLoopGroup(); // 接受新连接 EventLoopGroup workerGroup = new NioEventLoopGroup(); // 处理已建立的连接 try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) .childHandler(new MyInitializer()); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } ``` --- #### 6. **ServerBootstrap / Bootstrap** 这两个类分别用于启动服务器和服务端/客户端程序。 - **区别**: - `ServerBootstrap`: 专为服务器设计。 - `Bootstrap`: 主要针对客户端场景。 - **初始化代码片段**: ```java ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(group) .channel(NioServerSocketChannel.class) .childHandler(new InitializerClass()); ``` --- #### 7. **Unpooled 类** 当不需要频繁创建缓冲区时,可以直接使用静态工具类 `Unpooled` 创建 ByteBuf 对象。 ```java ByteBuf buffer = Unpooled.buffer(1024); // 分配大小为 1024 字节的缓冲区 buffer.writeBytes("Hello".getBytes()); // 写入字节数组 ``` --- #### 8. **ChannelFuture** `ChannelFuture` 表示异步操作的结果。由于 Netty 是全异步框架,因此所有的 I/O 操作都会返回一个 Future 对象[^3]。 - **特点**: 支持回调函数注册。 - **示例**: ```java ChannelFuture future = channel.closeFuture(); // 注册关闭事件 future.addListener(f -> { if (f.isSuccess()) { System.out.println("Connection closed successfully."); } else { f.cause().printStackTrace(); } }); ``` --- #### 总结 上述列举的是 Netty 中最常使用的几个核心 API。它们共同构成了 Netty 的基础架构,开发者可以通过组合这些模块快速构建高性能的网络应用。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NettyBoy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值