美文网首页
netty之ByteBuf

netty之ByteBuf

作者: hello_kd | 来源:发表于2020-02-27 14:34 被阅读0次

    ByteBuf是netty用于替代nio的ByteBuffer,存储字节的数据容器,相比于ByteBuffer,ByteBuf提供了更加强大和灵活的功能。主要表现在以下几个方面

    • capacity是可扩展的,不像ByteBuffer一经创建,就固定不变了。
    • 有两个索引,readIndex和writeIndex,分别用于读索引和写索引,而无需像ByteBuffer那样使用flip方法。
    • 方法支持链式调用
    • 引用计数
    • 支持池化

    具体与ByteBuffer有啥区别,可以参考这篇:nio之ByteBuffer

    readerIndex and writerIndex

    ByteBuf通过readerIndex和writerIndex将一个buffer划分为3个区域,如图


    1.1.png
    discardable bytes

    该区域是已经读取过的字节数据,因此称为可丢弃字节。在一个buffer刚创建时,该区域为的字节数为0,随着readerIndex的增加(读操作),该区域也会跟着扩大。可通过调用discardReadBytes()方法来回收该区域。其实就是将readerIndex和writerIndex的指针同时往前移动,移动的数为readerIndex的值,也就是读过的字节数。通过源码更能看出来。

    public ByteBuf discardReadBytes() {
        if (readerIndex == 0) {
            ensureAccessible();
            return this;
        }
    
        if (readerIndex != writerIndex) {
            setBytes(0, this, readerIndex, writerIndex - readerIndex);
            writerIndex -= readerIndex;
            adjustMarkers(readerIndex);
            readerIndex = 0;
        } else {
            ensureAccessible();
            adjustMarkers(readerIndex);
            writerIndex = readerIndex = 0;
        }
        return this;
    }
    

    下面这2张图为回收之前和之后的


    1.2.png
    readable bytes

    该区域是可读取的字节数据,buffer中以read和skip开头的方法被调用都会增加readerIndex的值。若读取的方法参数是另一个ByteBuf,那么目标ByteBuf的writerIndex也会随着增加。

    writable bytes

    该区域是可写的,buffer中还未被使用的区域。buffer中以write开头的方法被调用都会增加writerIndex的值,若写的方法参数是另一个buffer,那么目标ByteBuf的readerIndex的值。

    ByteBuffer使用模式

    ByteBuf与ByteBuffer一样,提供了heap buffer和direct buffer。作用与ByteBuffer类似,这边不再解释了,可通过hasArray方法判断buffer是heap的还是direct的,除了这两者,ByteBuf还提供另一种模式,组合模式CompositeByteBuf。该模式的buffer主要是组合多个ByteBuf对象,基本的使用方式如:

    ByteBuf byteBuf1 = Unpooled.directBuffer();
    byteBuf1.writeBytes("hello".getBytes());
    
    ByteBuf byteBuf2 = Unpooled.wrappedBuffer("world".getBytes());
    
    CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();
    compositeByteBuf.addComponent(byteBuf1);
    compositeByteBuf.addComponent(byteBuf2);
    
    for (int i = 0; i < compositeByteBuf.numComponents(); i++) {
        ByteBuf byteBuf = compositeByteBuf.component(i);
        System.out.println(byteBuf.toString(CharsetUtil.UTF_8));
    }
    

    这种方式对自定义消息体协议有很大的帮组作用,比如http协议中,消息体由header和body两部分组成,那么对于组合buffer来说,就可以针对这两部分分别写入和读取,极大简化了对消息体的解析。

    对于一个buffer的创建,一般推荐使用Unpooled这个类提供的静态方法来创建,而不是直接通过ByteBuf实现类的构造方法来创建。从该类的名字就可看出创建出来的buffer是未池化的。创建buffer的方式主要有3种,一种是直接分配新的空间;一种是wrap包装已存在的数据,该种方式对buffer或者是包装的对象的修改都是对对方可见的,也就是会直接影响到对方;还有一种是copy现有的数据,这种方式相当于两份独立的数据,互不干扰。

    ByteBuf的其他作用如引用计数、池化,这些在本文先不介绍,放在后面与netty的其他组件一起介绍。本文只是介绍了ByteBuf的基础内容,具体的如何使用以及其他内容可参考netty的api。

    相关文章

      网友评论

          本文标题:netty之ByteBuf

          本文链接:https://www.haomeiwen.com/subject/dfxmchtx.html