Netty之ByteBuf

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 中的数据以二进制10表示一下:

用老款的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章