Netty之ByteBuf
先放一段代码
package com.syuez;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
public class ByteBufTest {
public static void main(String[] args) {
ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(9, 100);
print("allocate ByteBuf(9, 100)", buffer);
// write 方法改变写指针,写完之后写指针未到 capacity 的时候,buffer 仍可写。
buffer.writeBytes(new byte[]{1,2,3,4});
print("writeBytes(1,2,3,4)", buffer);
// write 方法改变写指针,写完之后写指针未到 capacity 的时候,buffer 仍然可写,
// 写完 int 类型之后,写指针增加 4 。
buffer.writeInt(12); // java 中 int 占 4个字节
print("writeInt(12)", buffer);
// write 改变写指针,写完之后写指针等于 capacity 的时候,buffer 不可写。
buffer.writeBytes(new byte[]{5});
print("writeBytes(5)", buffer);
// write 方法改变写指针,写的时候发现 buffer 不可写则开始扩容,扩容之后 capacity 随即改变。
buffer.writeBytes(new byte[]{6});
print("writeBytes(6)", buffer);
// get 方法不改变读指针
System.out.println("getByte(3) return: " + buffer.getByte(3));
System.out.println("getShort(3) return: " + buffer.getShort(3));
System.out.println("getInt(3) return: " + buffer.getInt(3));
print("getByte()", buffer);
// set 方法不改变读写指针
buffer.setByte(buffer.readableBytes() + 1, 0);
print("setByte()", buffer);
// read 方法改变读指针
byte[] dst = new byte[buffer.readableBytes()];
buffer.readBytes(dst);
print("readBytes(" + dst.length + ")", buffer);
}
private static void print(String action, ByteBuf buffer) {
System.out.println("after ===========" + action + "============");
System.out.println("容量 —— capacity(): " + buffer.capacity());
System.out.println("最大容量 —— maxCapacity(): " + buffer.maxCapacity());
System.out.println("读指针位置 —— readerIndex(): " + buffer.readerIndex());
System.out.println("可读字节数 —— readableBytes(): " + buffer.readableBytes());
System.out.println("是否可读 —— isReadable(): " + buffer.isReadable());
System.out.println("写指针位置 —— writerIndex(): " + buffer.writerIndex());
System.out.println("可写字节数 —— writableBytes(): " + buffer.writableBytes());
System.out.println("是否可写 —— isWritable(): " + buffer.isWritable());
System.out.println("可写最大字节数 —— maxWritableBytes(): " + buffer.maxWritableBytes());
System.out.println();
}
}
ByteBuf 的结构:
ByteBuf 是一个字节容器,也就是说字节是 ByteBuf 中的最小单位,指针每移动1个单位就是读取1字节的数据。
在上面的代码中有getByte(3)
、getShort(3)
、getInt(3)
三个函数,它们的输出分别如下:
getByte(3) return: 4
getShort(3) return: 1024
getInt(3) return: 67108864
第一次看的时候我有些懵逼,除了知道4是怎么来的,剩下两个不知道是如何计算的。后来研究了一下,算是明白一点了。
首先看new byte[]{1,2,3,4}
,这是一个 byte 数组,刚开始我以为这里的1,2,3,4 是普通的数字(int),在 Java 中 int 占4个字节,而这里的1,2,3,4是 byte 类型,只占1个字节。byte[]{1,2,3,4}
和int[]{1,2,3,4}
完全是不一样的东西,真的是基础不牢,地动山摇。
上面的代码中,总共向 buffer 写入了4次数据:
buffer.writeBytes(new byte[]{1, 2, 3, 4});
buffer.writeInt(12);
buffer.writeBytes(new byte[]{5});
buffer.writeBytes(new byte[]{6});
除了12是 int 占4个字节,其他都只占1个字节。把 buffer 中的数据以二进制1
和0
表示一下:
用老款的Window计算器看下
左下角有字节、字、双字和四字,这里说下,八个比特(Bit)称为一个字节(Byte),两个字节称为一个字(Word),两个字称为一个双字(Dword),两个双字称为一个四字(Qword)。这里容易弄混。
int 12 是4字节,也就是双字:0000 0000 0000 0000 0000 0000 0000 0001
,其他都是1字节的。
那么图片上就是 buffer 的二进制bit表示了。
getByte(3)
就是索引3的位置开始,1个字节长度的数据0000 0100
,也就是4。
getShort(3)
就是索引3的位置开始,2个字节长度的数据(Java中short占2个字节)0000 0100 0000 0000
,就是1024。
getInt(3)
就是索引3的位置开始,4个字节长度的数据0000 0100 0000 0000 0000 0000 0000 0000
,就是67108864。
本文代码部分摘自《跟闪电侠学Netty》第7章