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中的属性
ByteBuf
内部使用三个指针来指导各个方法如何读取数据, 如何写入数据
2.1 writerIndex
- 每次调用writeXXX方法的时候都会更新
writerIndex
- 从0开始计数
- 每次写入数据, 会更新
writerIndex
写一个字节就+1, 写n个字节就+n
buf.writeByte(i);
可写的位置是 writerIndex ~ capacity 的位置
2.2 readerIndex
执行 readXXX() 方法会更新
readerIndex
- 可读的位置是 readerIndex ~ writerIndex 的位置
3. 通过Unpooled构造ByteBuf实例
- Netty提供的一个专门用来操作缓冲区(即Netty的数据容器)的
io.netty.buffer.Unpooled
工具类, 顾名思义造出来的ByteBuf是非池化的 (池化的可以重复利用) - 可以直接创造操作各种不同
ByteBuf
的实例, 实际上使用的是UnpooledByteBufAllocator._DEFAULT_
来创建1. 创建一个空的ByteBuf对象
//创建一个对象, 该对象包含一个数组 arr, 是一个 byte[10]
//netty的ByteBuf不需要使用flip,进行反转
ByteBuf buf = Unpooled.buffer(10);
for (int i = 100; i < 100 + 5; i++) {
buf.writeByte(i);
}
System.out.println("capacity = " + buf.capacity());
System.out.println("readableBytes = " + buf.readableBytes());
while (buf.readableBytes() > 0) {
System.out.println(buf.readByte());
}
2. 创造一个使用堆外内存的ByteBuf对象
io.netty.buffer.Unpooled#directBuffer(int, int)
这样当操作系统在内核态下想要读取数据, 就不需要拷贝后才能读取了3. 从目标复制数据
复制操作如果目标数据量大, 则会浪费内存空间ByteBuf buf = Unpooled.copiedBuffer("hello world", StandardCharsets.UTF_8);
if (buf.hasArray()) {
byte[] content = buf.array();//获取buf中的byte数组, 数组可能hello world没用满, 其他填充的就是默认值, readerIndex不变
System.out.println(buf);
String s1 = new String(content, StandardCharsets.UTF_8);// 打印的字符串后面可能会有乱码
System.out.println(s1);
String s2 = buf.toString(StandardCharsets.UTF_8); //完整的 hello world
System.out.println(s2);
//遍历打印每个字节
while (buf.isReadable()) { // writerIndex > readerIndex;
//System.out.println(buf.getByte(1)); //这种方式不会改变readerIndex的值
System.out.println(buf.readByte()); //这种方式会改变readerIndex的值
}
}
4. 组合多个ByteBuf
io.netty.buffer.Unpooled#compositeBuffer()
使用 CompositeByteBuf
可以理解就是一个视图
零复制(零拷贝) 的一种方案
5. 直接包装byte[]
多个byte[], 还是使用 CompositeByteBuf
也是零拷贝的一种方案