ByteBuf:Netty的数据容器

2023年 10月 11日 30.6k 0

网络传输的基本单位总是字节,JDK使用ByteBuffer作为Nio网络编程的数据容器,但是这个类使用过于复杂,存在一些缺点,例如:它不支持扩容、读写模式切换需要经常调用flip(),导致开发者经常因为忘记调用而导致无法读取写入的数据。

Netty使用ByteBuf来代替JDK的ByteBuffer,它有以下优点:

  • 支持扩容。
  • 分别维护读写索引,无需调用flip()
  • 支持链式调用。
  • 支持引用技术、池化,对象和内存可以复用。
  • CompositeByteBuf实现了透明的零拷贝。
  • 1. 工作模式

    ByteBuf分别维护读写索引readerIndex和writerIndex,写数据时writerIndex不断递增,读数据时readerIndex不断递增,readerIndex达到writerIndex代表无数据可读,writerIndex达到capacity代表不可写。

    通过这种方式,ByteBuf将缓冲区的数据分成了三段,分别是:

    数据段 范围
    可丢弃字节 0~readerIndex
    可读字节 readerIndex~writerIndex
    可写字节 writerIndex~capacity

    如何回收这部分「可丢弃字节」呢?ByteBuf提供了discardReadBytes()方法,它会移动readerIndex和writerIndex,同时将「可读字节」的数据向前复制。由于会导致内存复制,因此不建议频繁调用此方法。

    ByteBuf还提供了clear()方法用来清空缓冲区,它仅仅重置索引,不会有任何的内存复制,因此它速度极快。
    image.png

    1.1 顺序读写和随机读写

    ByteBuf支持顺序读写和随机读写,顺序读写会移动读写索引,随机读写不会。

    顺序读写的方法名以read和write开头,随机读写的方法名以get和set开头。

    除了可以往ByteBuf写入基本的字节数组外,还可以写入Java八大基本数据类型,Netty自己会完成字节的转换。
    例如,往HeapByteBuf写入一个int,源码如下:

    static void setInt(byte[] memory, int index, int value) {
        memory[index]     = (byte) (value >>> 24);
        memory[index + 1] = (byte) (value >>> 16);
        memory[index + 2] = (byte) (value >>> 8);
        memory[index + 3] = (byte) value;
    }
    

    往ByteBuf写数据的API:

    方法 说明
    writeBytes() 写入字节数组
    writeByte() 写入一个字节
    writeShort() 写入一个short,2字节
    writeInt() 写入一个int,4字节
    writeLong() 写入一个long,8字节
    writeFloat() 写入一个float,4字节
    writeDouble() 写入一个double,8字节
    writeChar() 写入一个char,2字节,高位被忽略
    writeBoolean() 写入一个boolean,1字节

    从ByteBuf中读数据API同上,把write改为read即可。

    以上两种是顺序读写,会移动读写索引,写入时如果空间不够,ByteBuf还会自动扩容,下面再说说随机读写。

    ByteBuf底层还是数组,一块连续的内存空间,可以根据索引快速定位,支持快速随机读写。随机读写方法以get和set开头,不会移动读写索引,如果index越界不会扩容,只会抛异常。

    如下是从HeapByteBuf中随机读取一个int值的源码:

    @Override
    public int getInt(int index) {
    // 检查index是否合理,有没有超出容量
    checkIndex(index, 4);
    return _getInt(index);
    }

    @Override
    protected int _getInt(int index) {
    return HeapByteBufUtil.getInt(array, index);
    }

    static int getInt(byte[] memory, int index) {
    return (memory[index] & 0xff)

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论