netty bytebuffer_计算系统基础答案详解

netty bytebuffer_计算系统基础答案详解1.ByteBuf与NIO中的ByteBuffer类似,Netty中以ByteBuf作为它的字节容器。ByteBuf相当于ByteBuffer的升级。有兴趣可以看一看>>之前NIO中的ByteBuffer的文章ByteBuf维护了两个不同的索引:一个用于读取,一个用于写入。读取时,读索引hi递增读取的字节数。写入时,写索引会递增写入的字节数。初始时两个索引都为0。当两个索引…


Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

1.ByteBuf概述

与NIO中的ByteBuffer类似,Netty中以ByteBuf作为它的字节容器。ByteBuf相当于ByteBuffer的升级。有兴趣可以看一看>>之前NIO中的ByteBuffer的文章
ByteBuffer存在一定的缺陷:

  1. ByteBuffer长度固定,一旦分配,则容量不能动态扩展和收缩
  2. ByteBuffer只有一个标识位置的指针,读写的时候需要手动的调用flip()方法来进行从写到读模式的切换,否则读出来的内容就是错误的。

ByteBuf维护了两个不同的索引:一个用于读取,一个用于写入。读取时,读索引递增读取的字节数。写入时,写索引会递增写入的字节数。初始时两个索引都为0。当两个索引相同时,也就是说数组中没有数据可读了。在试图读取会触发边界溢出异常。

整个ByteBuf被这两个指针最多分成三个部分,分别是可丢弃部分,可读部分和可写部分,可以用一张图直观的描述ByteBuf的结构,如下图所示:
在这里插入图片描述

从内存分配的角度看,ByteBuf可以分为两类:

  1. 堆内存字节缓存区
  • 优点:内存的分配和回收速度快,可以被JVM自动回收。
  • 缺点:如果是进行Socket的I/O读写,则需要额外做一次内存复制,即将堆内存对应的缓冲区复制到内核Channel中,因此性能会有一定程度的下降。
  1. 直接内存字节缓存区
    其优点和缺点刚好与“堆内存字节缓存区”相反,即优点:如果进行Socket的I/O读写,则不需要进行复制,而由于其是在堆外内存分配,因此相比堆内存其分配和回收就慢一些。

从内存回收的角度看,ByteBuf可以分为两类:

  1. 基于对象池的ByteBuf
  • 优点:可以重用ByteBuf对象。即可以提升内存的使用效率。
  • 缺点:内存池的管理和维护添加了复杂性。
  1. 普通ByteBuf
    其优缺点与ByteBuf相反,需要重复的创建对象,增加GC负担。

以上两种类型进行两两组合就构成了多种多样的ByteBuf,供用户选择使用。

2. ByteBuf的操作

2.1 ByteBuf的创建

首先肯定是要创建一个ByteBuf,更确切的说法就是要申请一块内存,后续可以在这块内存中执行写入数据读取数据等等一系列的操作。

那么如何创建一个ByteBuf呢?Netty中设计了一个专门负责分配ByteBuf的接口:ByteBufAllocator。该接口有一个抽象子类和两个实现类,分别对应了用来分配池化的ByteBuf和非池化的ByteBuf。
具体的层级关系如下图所示:
在这里插入图片描述

Netty又为我们提供了两个工具类:Pooled、Unpooled,分类用来分配池化的和未池化的ByteBuf
Unpooled类为例,提供了如下创建方法:

// 在堆上分配一个ByteBuf,并指定初始容量和最大容量
public static ByteBuf buffer(int initialCapacity, int maxCapacity) { 
   
    return ALLOC.heapBuffer(initialCapacity, maxCapacity);
}
// 在堆外分配一个ByteBuf,并指定初始容量和最大容量
public static ByteBuf directBuffer(int initialCapacity, int maxCapacity) { 
   
    return ALLOC.directBuffer(initialCapacity, maxCapacity);
}
// 使用包装的方式,将一个byte[]包装成一个ByteBuf后返回
public static ByteBuf wrappedBuffer(byte[] array) { 
   
    if (array.length == 0) { 
   
        return EMPTY_BUFFER;
    }
    return new UnpooledHeapByteBuf(ALLOC, array, array.length);
}
// 返回一个组合ByteBuf,并指定组合的个数
public static CompositeByteBuf compositeBuffer(int maxNumComponents){ 
   
    return new CompositeByteBuf(ALLOC, false, maxNumComponents);
}

ALLOC实际是一个ByteBufAllocator

private static final ByteBufAllocator ALLOC = UnpooledByteBufAllocator.DEFAULT;

ByteBufAllocator是一个专门负责ByteBuf分配的接口,对应的Unpooled实现类就是UnpooledByteBufAllocator。在UnpooledByteBufAllocator类中可以看到UnpooledByteBufAllocator.DEFAULT变量是一个final类型的静态变量

public static final UnpooledByteBufAllocator DEFAULT =
            new UnpooledByteBufAllocator(PlatformDependent.directBufferPreferred());
2.2 写操作

ByteBuf中定义了两类方法可以往ByteBuf中写入内容:writeXX() 和 setXX()。setXX是替换指定位置的值,而writeXX是想当前写指针写入数据后递增指针。
比如:setByte(int index, int value)表示将指定位置上的内容修改为指定的byte的值高24位上的内容将被丢弃。
why?Java中一个int占4个byte字节,即32bit(位),所以就会存在当写入一个byte时,参数用int来传值时,高24位的内容会被丢弃。这是因为一个int被拆成了4个byte,而写入一个byte到指定的位置时,那么其余的3个byte就被丢弃了,也就是丢弃的24位。

2.2 读操作

跟写操作一样,ByteBuf的读操作也有两种方法,分别是getXX()和readXX()。

3. 示例

public void test1() { 
   
	CompositeByteBuf message = Unpooled.compositeBuffer();
	ByteBuf header = Unpooled.buffer();
	ByteBuf body = Unpooled.directBuffer();
	message.addComponents(header, body);
	for(ByteBuf buf:message) { 
   
	    System.out.println(buf.toString());
	}
	int length = message.readableBytes();
	byte[] array = new byte[length];
	//将字节读到array数组中
	message.getBytes(message.readerIndex(), array);
}

随机访问索引和数据一样,ByteBuf的索引是从0开始,因此遍历非常容易

for(int i=0; i<buffer.capacity(); i++){ 
   
	byte b = buffer.getByte(i);
	System.out.println((char)b)
}

注意:get、set之类方法不会改变读写索引的位置。

顺序访问索JDK的ByteBuffer只有一个索引,这也是为什么必须调用flip()方法在读模式和写模式切换。

ByteBuf buf = Unpooled.buffer();
String str = "four you";
buf.writeBytes(str.getBytes());
System.out.println((char)buf.readByte());
int n = (char)buf.readerIndex();
System.out.println(n );

ByteBuf的可读字节分段存储了实际的数据,新分配的、包装的或者复制的缓冲区默认的读写索引都为0,任何一read、skip开头的操作都会使readerIndex变化,当然write相关的方法一回事writerIndex会被增加。

ByteBuf buf = Unpooled.buffer();
String str = "four you";
buf.writeBytes(str.getBytes());
System.out.println(buf.writerIndex());
buf.skipBytes(3);
buf.writeByte('a');
int n = buf.readerIndex();
int m = buf.writerIndex();
System.out.println("readerIndex:"+n+"\nwriterIndex:"+m);

查找的例子:

ByteBuf buf = Unpooled.buffer();
String str = "four you";
buf.writeBytes(str.getBytes());
int n = buf.indexOf(0,buf.capacity()-1,(byte)'r');
System.out.println("readerIndex:"+n);

派生缓冲区
在ByteBuf中有一些方法slice、order等方法会返回一个新的ByteBuf实例,它具有自己的读写索引和标记索引,但是内部存储的数组是共享的。

ByteBuf buffer = Unpooled.copiedBuffer("four you", CharsetUtil.UTF_8);
ByteBuf bufCopy = buffer.slice(0,3);
System.out.println(bufCopy.toString(CharsetUtil.UTF_8));
//更新索引0处的字节
buffer.setByte(0,(byte)'j');
System.out.println(bufCopy.toString(CharsetUtil.UTF_8));

结果是打印出来的不一样,说明数据是共享的。

ByteBuff复制
如果真的需要一个真实的复制品,可以使用copy方法。

ByteBuf buffer = Unpooled.copiedBuffer("four you", CharsetUtil.UTF_8);
ByteBuf bufCopy = buffer.copy(0,3);
System.out.println(bufCopy.toString(CharsetUtil.UTF_8));
buffer.setByte(0,(byte)'j');
System.out.println(bufCopy.toString(CharsetUtil.UTF_8));

打印出的结果一样。说明数据是独立的。

下一篇:https://blog.csdn.net/TheLudlows/article/details/79532899

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/193324.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • HTML期末大作业~餐饮文化学生网页设计作业(HTML+CSS+JavaScript)[通俗易懂]

    HTML期末大作业~餐饮文化学生网页设计作业(HTML+CSS+JavaScript)[通俗易懂]HTML期末大作业~基于HTML+CSS+JavaScript饮食网站设计与实现关于HTML期末网页制作,大作业A+水平~饮食网页作业HTML+CSS+JavaScript实现,共有联系我们在线留言资质荣誉行业资讯成功案例新闻资讯产品中心发展历史关于我们8个页面!原始HTML+CSS+JS页面设计,可以学习学习,大学网页设计作业,~这是一个不错的网页制作,画面精明,非常适合初学者学习使用。作品演示1.关于我们2.产品中心3.新闻资讯4.资质荣誉5.在线留言6.

    2022年9月7日
  • Java课程设计之 学生成绩管理系统「建议收藏」

    Java课程设计之 学生成绩管理系统「建议收藏」实现内容:设计开发一个学生成绩管理系统(1)根据实现的功能,划分出合理的对象类,明确各个对象类之间的关系。为各个对象类设计正确的域和方法,为每个方法设计合理的方法体。同时,为对象类及内部的域和方法运用正确的修饰符。功能要求:(1)录入成绩(2)查询成绩(3)成绩排序(4)修改成绩(5)删除成绩(6)将数据保存在数据库表中该课程设计涉及MySQL数据库,建表操作,java操作SQL语句(JDBC数据库操作)以及JavaS

    2022年7月9日
  • Flash动画制作视频教程

    Flash动画制作视频教程Flash是由macromedia公司推出的交互式矢量图和Web动画的标准,由Adobe公司收购。做Flash动画的人被称之为闪客。网页设计者使用Flash创作出既漂亮又可改变尺寸的导航界面以及其他奇特的效果。Flash的前身是FutureWave公司的FutureSplash,是世界上第一个商用的二维矢量动画软件,用于设计和编辑Flash文档。1996年11月,美国Macromedi

    2022年6月1日
  • 黑盒测试c语言用例,黑盒测试用例设计技术包括_测试用例包括什么_常用黑盒测试用例设计(4)…

    黑盒测试c语言用例,黑盒测试用例设计技术包括_测试用例包括什么_常用黑盒测试用例设计(4)…因此,可以把全部输入数据合理地划分为若干等价类,在每一个等价类中取一个数据作为测试的输入条件,这样就可以用少量的代表性测试数据,来取得较好的测试结果。黑盒测试用例设计技术包括*是指对于程序的规格说明来说,是合理的有意义的输入数据构成的集合。利用它可以检验程序是否实现预先规定的功能和性能。在具体问题中,有效等价类可以是一个,也可以是多个。有效等价类*是指对于程序的规格说明…

    2022年6月13日
  • 二叉树性质及证明「建议收藏」

    二叉树性质及证明「建议收藏」二叉树性质及证明(1)规定根节点层次为0,则一棵非空二叉树的第i层上最多有2i个结点。(2)规定根节点层次为0,则深度为k的二叉树的最大结点数为2(k+1)-1。(3)具有n个结点的完全二叉树的深度k为不超过lb(n+1)-1的最大整数。(4)对于一棵非空二叉树,如果叶节点个数为n0,度为2的结点数为n2,则有n0=n2+1。(5)对于具有n个结点的完…

    2022年5月31日
  • 麦克风声源定位原理_基于麦克风阵列的声源定位算法之GCC-PHAT

    麦克风声源定位原理_基于麦克风阵列的声源定位算法之GCC-PHAT目前基于麦克风阵列的声源定位方法大致可以分为三类:基于最大输出功率的可控波束形成技术、基于高分辨率谱图估计技术和基于声音时间差(time-delayestimation,TDE)的声源定位技术。基于TDE的算法核心在于对传播时延的准确估计,一般通过对麦克风间信号做互相关处理得到。进一步获得声源位置信息,可以通过简单的延时求和、几何计算或是直接利用互相关结果进行可控功率响应搜索等方法。这类算法实现…

    2022年9月22日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号