原文链接:https://www.cnblogs.com/wuweishuo/p/10854421.html
Netty中读写以ByteBuf为载体进行交互
ByteBuf的结构
- ByteBuf以readerIndex和writerIndex划分为三块区域,废弃字节,可读字节,可写字节。每次从ByteBuf读取一个字节时readerIndex+1,写入一个字节时writerIndex+1。
- 废弃字节,这部分的数据是无效的,范围为0~readerIndex-1
- 可读字节,从ByteBuf读取的数据都来自这块区域,范围为readerIndex~writerIndex-1,当readerIndex与writerIndex相等时不可读。
- 可写字节,写入的数据存放的区域,范围为writerIndex~capacity,当capacity与writerIndex相等时不可写,但是ByteBuf还有一个maxCapacity,容量不足时可以进来扩容,当容量超过maxCapacity时会报错。
读取
ByteBuf byteBuf = Unpooled.copiedBuffer("hello world".getBytes());//判断是否有可读的字节System.out.println(byteBuf.isReadable());//返回可读字节数System.out.println(byteBuf.readableBytes());//返回当前的读指针System.out.println(byteBuf.readerIndex());while (byteBuf.isReadable()) {//以read开头的方法都是读取方法,readInt、readBoolean等byteBuf.readByte();}System.out.println(byteBuf.readerIndex());//设置读指针byteBuf.readerIndex(0);//将当前可读数据都读取到byte[]中byteBuf.readBytes(new byte[byteBuf.readableBytes()]);
写入
//分配capacity为9,maxCapacity为12的byteBufByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(9, 12);//返回可写字节数System.out.println(byteBuf.writableBytes());//判断是否可写System.out.println(byteBuf.isWritable());//以write开头的都是写入方法byteBuf.writeByte(1);byteBuf.writeInt(1);byteBuf.writeBytes(new byte[]{1,2,3,4});//获取写指针System.out.println(byteBuf.writerIndex());//这时writerIndex==capacitySystem.out.println(byteBuf.writableBytes());System.out.println(byteBuf.isWritable());//再写入将扩容byteBuf.writeByte(1);System.out.println(byteBuf.isWritable());System.out.println(byteBuf.writableBytes());//扩容后仍然不足存放将报错//byteBuf.writeInt(1);//设置写指针byteBuf.writerIndex(0);System.out.println(byteBuf.isWritable());System.out.println(byteBuf.writableBytes());byteBuf.writeInt(1);
引用计数
release() 与 retain()
- netty使用的是堆外内存,不被jvm管理,所以需要我们手动释放。
- netty使用引用计数管理ByteBuf,如果没有地方引用一个ByteBuf,将直接回收底层内存。
- 一个ByteBuf被创建时引用为1,retain()将使引用+1,release()使引用-1,为0时将被回收。
- 一般遵循谁retain()(包括创建)谁release()
slice()、duplicate()、copy()
- slice()截取可读字节区域返回,新的ByteBuf的maxCapacity为旧的readableBytes(),但底层内存和引用共用
- duplicate()为ByteBuf的浅拷贝,读写指针与旧的无关,但底层内存和引用共用
- copy()为深拷贝,读写指针、引用和内存都无关
- slice()和duplicate()不会增加引用计数,而retainedSlice() 与 retainedDuplicate()会增加计数。
参考资料
Netty实战
Netty 入门与实战:仿写微信 IM 即时通讯系统