netty的byteBuf使用介绍

296 阅读3分钟

1. 背景

最近看了公司的自定义的传输数据格式,netty客户端接收到数据后,依照一定的规则来解码,防止粘包合拆包,解码过程中就使用到了netty的byteBuf不常见的一些API, 重要哈,ByteBuf就是数据传输载体

2. 使用说明

ByteBuf工作机制:ByteBuf维护了两个不同的索引,一个用于读取,一个用于写入。readerIndex和writerIndex的初始值都是0,当从ByteBuf中读取数据时,它的readerIndex将会被递增(它不会超过writerIndex),当向ByteBuf写入数据时,它的writerIndex会递增。

名称以readXXX或者writeXXX开头的ByteBuf方法,会推进对应的索引,而以setXXX或getXXX开头的操作不会。

在读取之后,0~readerIndex的就被视为discard的,调用discardReadBytes方法,可以释放这部分空间

readerIndex和writerIndex之间的数据是可读取的。writerIndex和capacity之间的空间是可写的,

划分为可丢弃分部分、可读部分、可写部分

ByteBuf.readableBytes() 返回可读的字节数

ByteBuf.readable() 是否有可读的内容

readableBytes() 表示 ByteBuf 当前可读的字节数,它的值等于 writerIndex-readerIndex,如果两者相等,则不可读,isReadable() 方法返回 false

writeBytes(byte[] src) 与 buffer.readBytes(byte[] dst)

writeByte() 表示往 ByteBuf 中写一个字节,而 buffer.readByte() 表示从 ByteBuf 中读取一个字节,类似的 API 还有 writeBoolean()、writeChar()、writeShort()、writeInt()、writeLong()、writeFloat()、writeDouble() 与 readBoolean()、readChar()、readShort()、readInt()、readLong()、readFloat()、readDouble()

一张图说明我理解的ByteBuf结构

image.png

3. 代码demo

public class TestByteBuf {

    @Test
    public void test01(){
        //创建一个容量为10的ByteBuf
        ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(10);
        System.out.println(buf);
    }


    @Test
    public void test02(){
        //申请长度是10的buffer
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(10);
        //写入5个长度的字节数组
        byte[] bytes = new byte[]{1, 2, 3, 4, 5};
        byteBuf.writeBytes(bytes);
        System.out.println(byteBuf);

        //再次写入5个
        byteBuf.writeBytes(bytes);
        System.out.println(byteBuf);
    }


    @Test
    public void test03(){
        //申请长度是10的buffer
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(10);

        //写入5个长度的字节数组
        byte[] bytes = new byte[]{1, 2, 3, 4, 5};
        byteBuf.writeBytes(bytes);
        System.out.println(byteBuf);

        //直接读取下一个字节
        System.out.println(byteBuf.readByte());
        System.out.println(byteBuf);

        System.out.println(byteBuf.readByte());
        System.out.println(byteBuf);

        //读取自己数组

        byteBuf.readBytes(new byte[3]);
        System.out.println(byteBuf);

    }


    @Test
    public void test04(){
        //申请长度是10的buffer
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(10);

        //写入5个长度的字节数组
        byte[] bytes = new byte[]{1, 2, 3, 4, 5};
        byteBuf.writeBytes(bytes);

        //设置一个mark
        byteBuf.markReaderIndex();

        //读取自己数组
        System.out.println(byteBuf.readByte());
        System.out.println(byteBuf);

        //重置到mark,就是把readerIndex放到你刚刚mark的位置
        byteBuf.resetReaderIndex();

        //读取自己数组
        System.out.println(byteBuf.readByte());
        System.out.println(byteBuf);
    }
    
}


@Test
public void test05() {
    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);
    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);
    short aShort = buffer.getShort(3);
    // get 方法不改变读写指针, getShort这种写法是从第三个索引开始读取连个该字节
    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();
}