1. ByteBuf是什么

Java 的NIO使用的是ByteBuffer 来作为网络传输缓冲区, 它有比较多的缺点, 比如读写需要flip();

Netty为了让程序员编写网络程序的时候更加省心, 则设计了ByteBuf作为新的接口
ByteBuf 通过各种实现消除调 ByteBuffer 的各种缺点
其实Netty在最终调用JDK的NIO接口的时候, 还是转成了 ByteBuffer 去进行处理
但是我们程序员在使用Netty编程的时候就不需要再被 ByteBuffer 恶心了

Netty在进行读写事件处理的时候

  • 从网络读取的时候, 将的数据, 抽象成ByteBuf这种对象来交给 pipeline 中的第一个handler进行处理
  • 发送数据的时候, 消息也要封装成ByteBuf再Netty通过JDK的标准接口发送出去发送

    2. ByteBuf中的属性

    image.png

    ByteBuf内部使用三个指针来指导各个方法如何读取数据, 如何写入数据

2.1 writerIndex

  • 每次调用writeXXX方法的时候都会更新writerIndex
  • 从0开始计数
  • 每次写入数据, 会更新 writerIndex
  • 写一个字节就+1, 写n个字节就+n

    1. buf.writeByte(i);

    可写的位置是 writerIndex ~ capacity 的位置
    image.png

    2.2 readerIndex

  • 执行 readXXX() 方法会更新 readerIndex

  • 可读的位置是 readerIndex ~ writerIndex 的位置

    image.png

3. 通过Unpooled构造ByteBuf实例

  • Netty提供的一个专门用来操作缓冲区(即Netty的数据容器)的 io.netty.buffer.Unpooled工具类, 顾名思义造出来的ByteBuf是非池化的 (池化的可以重复利用)
  • 可以直接创造操作各种不同 ByteBuf 的实例, 实际上使用的是 UnpooledByteBufAllocator._DEFAULT_ 来创建

    1. 创建一个空的ByteBuf对象

    1. //创建一个对象, 该对象包含一个数组 arr, 是一个 byte[10]
    2. //netty的ByteBuf不需要使用flip,进行反转
    3. ByteBuf buf = Unpooled.buffer(10);
    4. for (int i = 100; i < 100 + 5; i++) {
    5. buf.writeByte(i);
    6. }
    7. System.out.println("capacity = " + buf.capacity());
    8. System.out.println("readableBytes = " + buf.readableBytes());
    9. while (buf.readableBytes() > 0) {
    10. System.out.println(buf.readByte());
    11. }

    2. 创造一个使用堆外内存的ByteBuf对象

    io.netty.buffer.Unpooled#directBuffer(int, int)
    这样当操作系统在内核态下想要读取数据, 就不需要拷贝后才能读取了

    3. 从目标复制数据

    复制操作如果目标数据量大, 则会浪费内存空间
    image.png
    1. ByteBuf buf = Unpooled.copiedBuffer("hello world", StandardCharsets.UTF_8);
    2. if (buf.hasArray()) {
    3. byte[] content = buf.array();//获取buf中的byte数组, 数组可能hello world没用满, 其他填充的就是默认值, readerIndex不变
    4. System.out.println(buf);
    5. String s1 = new String(content, StandardCharsets.UTF_8);// 打印的字符串后面可能会有乱码
    6. System.out.println(s1);
    7. String s2 = buf.toString(StandardCharsets.UTF_8); //完整的 hello world
    8. System.out.println(s2);
    9. //遍历打印每个字节
    10. while (buf.isReadable()) { // writerIndex > readerIndex;
    11. //System.out.println(buf.getByte(1)); //这种方式不会改变readerIndex的值
    12. System.out.println(buf.readByte()); //这种方式会改变readerIndex的值
    13. }
    14. }

4. 组合多个ByteBuf

io.netty.buffer.Unpooled#compositeBuffer()
使用 CompositeByteBuf
可以理解就是一个视图
零复制(零拷贝) 的一种方案

5. 直接包装byte[]

image.png
多个byte[], 还是使用 CompositeByteBuf
也是零拷贝的一种方案