netty源码阅读之ByteBuf之ByteBuf结构和重要API

主要分一下几点讲解:

1、ByteBuf结构

2、read、write、set方法

3、mark和reset方法

 

 

一、ByteBuf结构

我们找到ByteBuf源码,查看最前面的注释,有这样一段:

 * <pre>
 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      |                   |     (CONTENT)    |                  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity
 * </pre>

在netty里面,有几个重要的指针:

1、readerIndex,0到readerindex这里就是不读的数据,也就是抛弃的数据;从readerIndex开始读数据。

2、writerIndex,readerIndex到writerIndex这里就是没有读的数据,也就是可读的内容;从writeIndex开始写数据。

3、capacity,writerIndex到capacity这段数据就是我们可以往里面写的空间

4、maxCapacity,其实这里应该还有个maxCapacity(可以看做是在capacity后面),capacity到maxCapacity这里,是这个Byte还可以扩展的空间。

 

二、read、write、set方法

我们找到ByteBuf的read方法,发现它居然有这么多种实现:

   ...
    public abstract boolean readBoolean();
     
    public abstract byte  readByte();

    public abstract short readUnsignedByte();

    
    public abstract short readShort();

  
    public abstract short readShortLE();

    
    public abstract int   readUnsignedShort();

    
    public abstract int   readUnsignedShortLE();

  
    public abstract int   readMedium();

      ....

当然这里之列举了一部分,netty会根据数据的大小选择合适的read方法。

 

write也不用说了:

     ...
public abstract ByteBuf writeBoolean(boolean value);

   
    public abstract ByteBuf writeByte(int value);

    public abstract ByteBuf writeShort(int value);
   
    public abstract ByteBuf writeShortLE(int value);

    ...

 

set方法:

    ...    

    public abstract ByteBuf setBoolean(int index, boolean value);

    public abstract ByteBuf setByte(int index, int value);

    
    public abstract ByteBuf setShort(int index, int value);

   
    public abstract ByteBuf setShortLE(int index, int value);
    
    ...

read和write是做什么的不用多解释,这里我们介绍以下set,其实也就是在特定的index开始的位置设置上特定的值,可以从index位置开始,设置多个。

 

三、mark和reset方法

这里先介绍以下,mark我标记在某个位置,执行read或者write之后指针会变化,我用reset就可以设置回去原来mark的位置了:

    /**
     * Marks the current {@code readerIndex} in this buffer.  You can
     * reposition the current {@code readerIndex} to the marked
     * {@code readerIndex} by calling {@link #resetReaderIndex()}.
     * The initial value of the marked {@code readerIndex} is {@code 0}.
     */
    public abstract ByteBuf markReaderIndex();

    /**
     * Repositions the current {@code readerIndex} to the marked
     * {@code readerIndex} in this buffer.
     *
     * @throws IndexOutOfBoundsException
     *         if the current {@code writerIndex} is less than the marked
     *         {@code readerIndex}
     */
    public abstract ByteBuf resetReaderIndex();

    /**
     * Marks the current {@code writerIndex} in this buffer.  You can
     * reposition the current {@code writerIndex} to the marked
     * {@code writerIndex} by calling {@link #resetWriterIndex()}.
     * The initial value of the marked {@code writerIndex} is {@code 0}.
     */
    public abstract ByteBuf markWriterIndex();

    /**
     * Repositions the current {@code writerIndex} to the marked
     * {@code writerIndex} in this buffer.
     *
     * @throws IndexOutOfBoundsException
     *         if the current {@code readerIndex} is greater than the marked
     *         {@code writerIndex}
     */
    public abstract ByteBuf resetWriterIndex();

看看源码的注释就能明白

 

四、其他API

在一个开始我们也介绍过这几个指针,看看注释,就知道这些方法的作用:

/**
     * Returns the number of readable bytes which is equal to
     * {@code (this.writerIndex - this.readerIndex)}.
     */
    public abstract int readableBytes();

    /**
     * Returns the number of writable bytes which is equal to
     * {@code (this.capacity - this.writerIndex)}.
     */
    public abstract int writableBytes();

    /**
     * Returns the maximum possible number of writable bytes, which is equal to
     * {@code (this.maxCapacity - this.writerIndex)}.
     */
    public abstract int maxWritableBytes();

    /**
     * Returns {@code true}
     * if and only if {@code (this.writerIndex - this.readerIndex)} is greater
     * than {@code 0}.
     */
    public abstract boolean isReadable();

    /**
     * Returns {@code true} if and only if this buffer contains equal to or more than the specified number of elements.
     */
    public abstract boolean isReadable(int size);

    /**
     * Returns {@code true}
     * if and only if {@code (this.capacity - this.writerIndex)} is greater
     * than {@code 0}.
     */
    public abstract boolean isWritable();

    /**
     * Returns {@code true} if and only if this buffer has enough room to allow writing the specified number of
     * elements.
     */
    public abstract boolean isWritable(int size);

    /**
     * Sets the {@code readerIndex} and {@code writerIndex} of this buffer to
     * {@code 0}.
     * This method is identical to {@link #setIndex(int, int) setIndex(0, 0)}.
     * <p>
     * Please note that the behavior of this method is different
     * from that of NIO buffer, which sets the {@code limit} to
     * the {@code capacity} of the buffer.
     */
    public abstract ByteBuf clear();

我们可以知道,ByteBuf的读写什么,其实就是不停地移动这些指针。初始的位置readerIndex和writerIndex的位置都是0。

 

五、AbstactByteBuf

首先我们查看一下这个类的关系图:

我们暂且不管下面的几个实现吧(下一篇再介绍),直接先看AbstractByteBuf,继承于ByteBuf,看这个类的源码的解释:

/**
 * A skeletal implementation of a buffer.
 */
public abstract class AbstractByteBuf extends ByteBuf {
...
}

a skeletal implementation。对buffer也就是ByteBuf的一个骨架式的实现。阅读源码多了,我们都知道这个套路,abstract一般就是对接口的骨架式实现。

继续看:

    int readerIndex;
    int writerIndex;
    private int markedReaderIndex;
    private int markedWriterIndex;
    private int maxCapacity;

前面介绍的那几个指针,都在这里体现出来了。

前面说过的maxCapacity:

protected AbstractByteBuf(int maxCapacity) {
        if (maxCapacity < 0) {
            throw new IllegalArgumentException("maxCapacity: " + maxCapacity + " (expected: >= 0)");
        }
        this.maxCapacity = maxCapacity;
    }

readableBytes()的实现:

 @Override
    public int readableBytes() {
        return writerIndex - readerIndex;
    }

writableBytes(),maxWritableBytes(),markReaderIndex(),resetReaderIndex()这几个不赘述,自行查看源码,简单。

然后我们看ByteBuf readerIndex(int readerIndex):

 @Override
    public ByteBuf readerIndex(int readerIndex) {
        if (readerIndex < 0 || readerIndex > writerIndex) {
            throw new IndexOutOfBoundsException(String.format(
                    "readerIndex: %d (expected: 0 <= readerIndex <= writerIndex(%d))", readerIndex, writerIndex));
        }
        this.readerIndex = readerIndex;
        return this;
    }

保证不越界,并且附上读指针。从这里我们开始留意到,ByteBuf很多都是返回this指针,方便链式调用。

看readByte():

  @Override
    public byte readByte() {
        checkReadableBytes0(1);
        int i = readerIndex;
        byte b = _getByte(i);
        readerIndex = i + 1;
        return b;
    }

我们看到,读的操作是委托到有一个下划线的_getByte(i)方法里面,别的readBool(),readInt()等这些方法,都是一个道理。

在这里,由于byte是一个字节,所以readerIndex是i+1;

如果是readInt():

  @Override
    public int readInt() {
        checkReadableBytes0(4);
        int v = _getInt(readerIndex);
        readerIndex += 4;
        return v;
    }

int 是个字节,那么就是加4。

至于下划线方法的实现,会委托给每种ByteBuf最终子类的实现,有各自的方法,这就关系到各个ByteBuf实现的区别了,后续的文章会继续讲解。(readableBytes(),writableBytes(),maxWritableBytes(),markReaderIndex(),resetReaderIndex()这些方法能够在这里实现是因为它们和底层的读写没有关系)

AbstractByteBuf通过对这些接口对外能够提供丰富的功能,这里是不是对抽象有了深一点的理解呢?抽象出接口,并实现一部分功能,具体的实现由方法里面的子类实现的方法去实现。

wirteByte方法也是一样的:

   @Override
    public ByteBuf writeByte(int value) {
        ensureAccessible();
        ensureWritable0(1);
        _setByte(writerIndex++, value);
        return this;
    }

后面的方法,自行查看源码,不赘述了。

关于ByteBuf的分类,请听下回分解

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值