当前位置: 首页 > 编程日记 > 正文

Netty - ByteBuf

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

1.ByteBuf类 - Netty的数据容器

ByteBuf维护了两个不同的索引:

  • readerIndex:用于读取
  • writerIndex:用于写入

起始位置都从0开始:

名称以read或者write开头的方法会更新ByteBuf对应的索引,而名称以set或者get开头的操作不会。 AbstractByteBuf#readByte 代码如下:

public byte readByte() {checkReadableBytes0(1);int i = readerIndex;byte b = _getByte(i);readerIndex = i + 1;// 这里更新了索引return b;
}

AbstractByteBuf#getByte 代码如下:

public byte getByte(int index) {checkIndex(index);return _getByte(index);// 直接返回,没有更新索引
}

2.ByteBuf的使用模式

(1)堆缓冲区

将数据存储在JVM的堆空间。

  • 好处:提供快速分配和释放4
  • 场景:遗留数据处理
public static void heapBuffer() {ByteBuf heapBuf = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhereif (heapBuf.hasArray()) { //检查 ByteBuf 是否有一个支撑数组byte[] array = heapBuf.array();//如果有,则获取对该数组的引用int offset = heapBuf.arrayOffset() + heapBuf.readerIndex();//计算第一个字节的偏移量int length = heapBuf.readableBytes();//获得可读字节数handleArray(array, offset, length);//使用数组、偏移量和长度作为参数调用你的方法}
}

如果hasArray()返回false,仍然去访问array()会抛出UnsupportedOperationException

(2)直接缓冲区

NIO在JDK1.4中引入的ByteBuffer类允许JVM实现通过本地调用来分配内存。直接缓冲区的内容将驻留在常规的会被垃圾回收的堆之外。 如果数据包含在一个在堆上分配的缓冲区中,在通过套接字发送它之前,JVM会在内部把缓冲区复制到一个直接缓冲区中。

  • 目的:避免在每次调用本地I/O操作之前(后)将缓冲区的内容复制到一个中间缓冲区(或者从中间缓冲区把内容复制到缓冲区)
  • 缺点:直接缓冲区的分配和释放较堆缓冲区昂贵
public static void directBuffer() {ByteBuf directBuf = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewhereif (!directBuf.hasArray()) {//检查 ByteBuf 是否由数组支撑。如果不是,则这是一个直接缓冲区int length = directBuf.readableBytes();//获取可读字节数byte[] array = new byte[length];//分配一个新的数组来保存具有该长度的字节数据directBuf.getBytes(directBuf.readerIndex(), array);//将字节复制到该数组handleArray(array, 0, length);//使用数组、偏移量和长度作为参数调用你的方法}
}

(3)复合缓冲区

为多个ByteBuf提供一个聚合视图,可以根据需要添加或者删除ByteBuf实例。 CompositeByteBuf ByteBuf的子类,提供一个将多个缓冲区表示为单个合并缓冲区的虚拟表示。CompositeByteBuf中的ByteBuf实例可能同时包含直接内存分配非直接内存分配

  • 通过JDK的ByteBuffer实现:创建一个包含两个ByteBuffer的数组来保存消息组件
public static void byteBufferComposite(ByteBuffer header, ByteBuffer body) {// Use an array to hold the message partsByteBuffer[] message =  new ByteBuffer[]{ header, body };// Create a new ByteBuffer and use copy to merge the header and bodyByteBuffer message2 =ByteBuffer.allocate(header.remaining() + body.remaining());message2.put(header);message2.put(body);message2.flip();
}
  • 使用CompositeByteBuf实现的复合缓冲区模式:
public static void byteBufComposite() {CompositeByteBuf messageBuf = Unpooled.compositeBuffer();ByteBuf headerBuf = BYTE_BUF_FROM_SOMEWHERE; // can be backing or directByteBuf bodyBuf = BYTE_BUF_FROM_SOMEWHERE;   // can be backing or directmessageBuf.addComponents(headerBuf, bodyBuf);//将 ByteBuf 实例追加到 CompositeByteBuf//...//删除位于索引位置为 0(第一个组件)的 ByteBufmessageBuf.removeComponent(0); // remove the header//循环遍历所有的 ByteBuf 实例for (ByteBuf buf : messageBuf) {System.out.println(buf.toString());}
}
  • 因为CompositeByteBuf可能不支持访问其支撑数组,访问CompositeByteBuf中的数据类似于直接缓冲区的模式:
public static void byteBufCompositeArray() {CompositeByteBuf compBuf = Unpooled.compositeBuffer();int length = compBuf.readableBytes();//获得可读字节数byte[] array = new byte[length];//分配一个具有可读字节数长度的新数组compBuf.getBytes(compBuf.readerIndex(), array);//将字节读到该数组中handleArray(array, 0, array.length);//使用偏移量和长度作为参数使用该数组
}

3.ByteBuf字节级操作

ByteBuf提供了许多超出基本读/写操作的方法用于修改数据。

(1)随机访问索引

第一个字节的索引:0, 最后一个字节的索引:capacity() - 1

public static void byteBufRelativeAccess() {ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewherefor (int i = 0; i < buffer.capacity(); i++) {byte b = buffer.getByte(i);System.out.println((char) b);}
}

(2)顺序访问索引

首先看下ByteBuf的内部分段:

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

After discardReadBytes():对可写分段的内容并没有任何保证,因为只是移动了可以读取的字节以及writerIndex,并没有对所有可写入的字节进行擦除写。

	  +------------------+--------------------------------------+|  readable bytes  |    writable bytes (got more space)   |+------------------+--------------------------------------+|                  |                                      |readerIndex (0) <= writerIndex (decreased)        <=        capacity

可以看出,ByteBuf被读索引写索引划分成了3个区域:

  • 可丢弃字节:已经被读过的字节,调用discardReadBytes()丢弃并回收空间(丢弃字节部分变为可写)。初始大小是0,存储在readerIndex中,随着read操作的执行而增加。
  • 可读字节:可读字节分段存储了实际数据。新分配的/包装的/复制的缓冲区的默认的readerIndex值为0。任何read或者skip开头的操作都将检索或者跳过位于当前readerIndex的数据,并且将它增加已读字节数。如果被调用的方法需要一个ByteBuf参数作为写入的目标,并且没有指定目标索引参数,那么该目标缓冲区的writerIndex也将被增加。如果尝试在缓冲区的可读字节数已经耗尽时从中读取数据,将抛出-IndexOutOfBoundsException 见下面代码
  • 可写字节:可写字节分段指一个未定义内容/写入就绪的内存区域。新分配的缓冲区的writerIndex的默认值是0。任何write开头的操作都将从当前的writerIndex处开始写数据,并将它增加已经写入的字节数。

readBytes(ByteBuf dst) 代码

public ByteBuf readBytes(ByteBuf dst) {readBytes(dst, dst.writableBytes());return this;
}
public ByteBuf readBytes(ByteBuf dst, int length) {if (checkBounds) {if (length > dst.writableBytes()) {throw new IndexOutOfBoundsException(String.format("length(%d) exceeds dst.writableBytes(%d) where dst is: %s", length, dst.writableBytes(), dst));}}readBytes(dst, dst.writerIndex(), length);dst.writerIndex(dst.writerIndex() + length);return this;
}

如何读取所有可读字节:

public static void readAllData() {ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewherewhile (buffer.isReadable()) {System.out.println(buffer.readByte());}
}

如何往可写字节分段写数据:

public static void write() {// Fills the writable bytes of a buffer with random integers.ByteBuf buffer = BYTE_BUF_FROM_SOMEWHERE; //get reference form somewherewhile (buffer.writableBytes() >= 4) {buffer.writeInt(random.nextInt());}
}

转载于:https://my.oschina.net/javamaster/blog/2996702

相关文章:

不要做浮躁的嵌入式系统工程师

每天读一遍&#xff0c;思考一下&#xff1a;我是否浮躁&#xff1f; 1、不要看到别人的回复&#xff0c;第一句话就说&#xff1a;给个代码吧&#xff01;你应该想想为什么。当你自己想出来再参考别人的提示&#xff0c;就会知道自己和别人思路的差异。 2、初学者请不要看…

Codeforces Round #300 A. Cutting Banner 水题

A. Cutting Banner Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/538/problem/ADescription A large banner with word CODEFORCES was ordered for the 1000-th onsite round of Codeforcesω that takes place on the Miami beach. Unfo…

ImportError:cannot import name ‘display‘ File “XX“, line 5, in <module> from IPython import display

导入错误问题的一个解决思路是&#xff0c;推断这是模块间版本不兼容带来的问题&#xff0c;先把模块卸载掉&#xff0c;再用conda install安装上。也就是让conda去协调模块间兼容性。

[高级]android应用开发之intent的妙用二

相信做android应用开发的朋友对intent组件都已经是相当熟悉了&#xff0c;这里鄙人总结一下intent的妙用&#xff0c;希望对大家有帮助。 intent妙用之列出所有已安装的应用程序列表 装载&#xff1a;http://blog.csdn.net/android_tutor/article/details/5724634 这篇文章写的…

windows 自动化目录大纲(各企业架构不一样,按需选择)

有需要做自动化的联系979122932,一起交流学习转载于:https://blog.51cto.com/7763608/2338668

Java设计模式之虚拟代理模式

描述&#xff1a;虚拟代理模式(Virtual Proxy)是一种节省内存的技术&#xff0c;它建议创建那些占用大量内存或处理复杂的对象时&#xff0c;把创建这类对象推迟到使用它的时候。在特定的应用中&#xff0c;不同部分的功能由不同的对象组成&#xff0c;应用启动的时候&#xff…

(已解决)ImportError attempted relative import with no known parent package

想要调用同一目录下的另一个py文件中的类&#xff0c;以下或许是可行的解决方案。 需要做到两点 1. 将主调文件的名称改为__init__.py 2. from 被调文件的文件名称(删去末尾.py) import 类名 不要在被调文件的文件名称前面加点&#xff01; 我的目录结构 我的调用方式 fro…

小红点功能控件

写在前面 本意是想把做过的东西沉淀一下&#xff0c;防止重复造轮子。后来想想自己在实现这个的过程中还是走了一点弯路的。虽然网上找的轮子很多&#xff0c;其实大多都华而不实或者功能太多&#xff0c;工作中实现的东西最重要的不是功能炫&#xff0c;而是稳定&#xff0c;一…

根据条件查找数组中的一条数据并放入缓存

protected MemberInfo GetCacheMemberInfo(string userName) { MemberInfo minfo new MemberInfo();//实体 minfo System.Web.HttpRuntime.Cache.Get("HotPP_" userName) as MemberInfo;//读缓存 if (minfo null) { M…

看我如何下载韩寒博客文章笔记

str()将整型数据转化为字符型数据转载于:https://www.cnblogs.com/sunshinewxz/p/4461432.html

怎样知道pip install 可以安装包的哪些版本

方法一&#xff1a; 思路很清晰&#xff0c;故意不给版本号&#xff0c;然后系统就告诉你&#xff0c;这样不行呀&#xff0c;可以用以下XX,XX,XX版本号 例如安装torchtext

异步编程之Promise(2):探究原理

异步编程系列教程&#xff1a; (翻译)异步编程之Promise(1)——初见魅力异步编程之Promise(2)&#xff1a;探究原理异步编程之Promise(3)&#xff1a;拓展进阶异步编程之Generator(1)——领略魅力异步编程之Generator(2)——剖析特性异步编程之co——源码分析动手实现Promise 在…

PC端、移动端手机竖拍原图压缩上传顺时针旋转90°的解决方案

问题背景 最近在做的项目中&#xff0c;不管是移动端还是后台系统都涉及到了手机照片压缩上传的问题&#xff0c;做完功能测试的时候发现图片回显的时候有些顺时针旋转了90&#xff08;竖拍照片&#xff0c;不管是ios还是android都存在这问题&#xff09;&#xff0c;后来百度了…

perl:cpanm安装方式的一种取代方法

笔者现在有一个cpanfile&#xff0c;里面需要安装的perl模块&#xff0c;github的作者给出的指令是 cpanm --installdeps . 而笔者的服务器没有cpanm&#xff0c;因为不是管理员也无法用apt安装 经过一番搜索&#xff0c;发现以下的替代方式&#xff1a; 依次在命令行输入 1…

elementUI源码修改的爬坑之旅

今天由于项目需要&#xff0c;想在Tree组件的前面增加一个icon图标&#xff0c;根据不同类型增加不同的图标&#xff0c;我修改了elementUI的源代码&#xff0c;发布到npm上去成功使用&#xff0c;记录下过程中所碰到的问题&#xff0c;首先看下最后的效果&#xff1a; 下面简单…

Sublime text3 快捷方式(windows平台)

1.Goto Anything-快速查找&#xff08;ctrl P&#xff09; 输入函数名可以快速找到函数输入#文本可以快速进行文件内文本匹配2.命令模式CtrlShiftP&#xff1a;打开命令面板 CtrlP&#xff1a;搜索项目中的文件 CtrlW&#xff1a;关闭当前打开文件 CtrlShiftW&#xf…

(已解决)ubuntu20.04 jar xvf XXX.zip报错-java.io.EOFException:Unexpected end of ZLIB input stream

报错截图 如下 我在服务器上解压缩defects4j-repos.zip&#xff0c;但是出现了如上错误。通过SFTP我把这个压缩包传到了本地win10上面&#xff0c;进行解压缩。本地解压缩软件(有图形界面的好处显现了)告诉我这个文件已经损坏。 原因分析 由于运行脚本涉及到一堆的文件下载&am…

Linux上传和下载

下载&#xff1a;sz 上传&#xff1a;rz

joomla网页无任何显示输出

joomla配置环境&#xff1a;LAMP 先打开php.ini display_errorsOn 网页显示报错 Class DOMDocument not found *********** 解决方法&#xff1a; 1.安装php-xml #yum install php-xml 2.重启apache&#xff08;CentOS&#xff09; #service httpd restart转载于:https://www…

【mysql的编程专题⑤】自定义函数

用户自定义函数(user-defined function,UDF) 是一种对mysql的扩展途径&#xff0c;其用法与内置函数相同 创建自定义函数 语法 create function function_name returns {string|integer|real|decimal} routine_body Example1 delimiter $ create function f1(gdate datetime) …

配深度学习环境要注意的不多,也就

1. 使用nvcc -V命令查看cuda版本&#xff0c;再在官网选择对应版本的pytorch。(是的不要根据python的版本去选择pytorch指令) 2. 用conda安装pytorch可能一直有cpuonly的玄学问题。(哪怕选择的是CUDA版本的pytorch安装命令)改用pip安装。 3. torchtext不会被顺带安装&#xf…

整理的一点MD5资料(第一部分)

MD5加密算法研究MD5简介&#xff1a; MD5的全称是Message-Digest Algorithm 5&#xff0c;在90年代初由MIT的计算机科学实验室和RSA Data Security Inc发明&#xff0c;经MD2、MD3和MD4发展而来。 Message-Digest泛指字节串(Message)的Hash变换&#xff0c;就是把一个任意长度的…

SQL学习(六)

1. INSERT 通用形式&#xff1a; INSERT INTO tablename [colname {,colname...}] {VALUES (expr &#xff5c;NULL &#xff5c; Subquery)} 例&#xff1a;1. insert into orders (ordno,month) values (1107.aug); 2. insert into swcusts select * from customers wh…

百练,4103,踩方格

百练&#xff0c;4103&#xff0c;踩方格 普通做法&#xff1a;&#xff08;也可以找规律&#xff09; #include #include//要调用memset函数&#xff0c;头文件 using namespace std; int visited[50][50];//开辟50*50的方格 int num0;//num为方案数 void ways(int i,int j,i…

BZOJ1747 [Usaco2005 open]Expedition 探险

首先我们可以发现如果错过了一个加油站&#xff0c;而继续往前走的时候没有油了&#xff0c;可以再假装之前经过加油站的时候加过油 于是我们维护一个大根堆&#xff0c;表示错过的加油站是哪些&#xff0c;每当没有油的时候从堆顶取出最大值加上去即可 1 /*******************…

Netty - ByteBuf索引管理

2019独角兽企业重金招聘Python工程师标准>>> 之前写过一篇文章介绍过JDK里面InputStream的mark(readlimit)和reset()方法&#xff0c;Java IO&#xff1a;使用mark/reset实现替换文件中字符串。相应的&#xff0c;可以通过调用markReaderIndex()/markWriterIndex()/…

DB2 9 利用开辟(733 测验)认证指南,第 1 部分: 数据库工具与编程步调(6)

运用基泉源基本理构建根本完毕语总结本教程向您引见了 DB2 利用挨次开辟的根本常识。在中缀任何开辟变乱之前&#xff0c;必须熟习差别规范的数据库工具。在本教程中&#xff0c;引见了几种初级的数据库工具。别名、序列工具和且则表凡是用于简化利用挨次代码。存储历程、函数和…

PHP 设计模式 笔记与总结(9)数据对象映射模式

【数据对象映射模式】 是将对象和数据存储映射起来&#xff0c;对一个对象的操作会映射为对数据存储的操作。例如在代码中 new 一个对象&#xff0c;使用数据对象映射模式就可以将对象的一些操作比如设置一些属性&#xff0c;就会自动保存到数据库&#xff0c;跟数据库中表的一…

inet_pton和inet_ntop函数

Linux下这2个IP地址转换函数&#xff0c;可以在将IP地址在“点分十进制”和“整数”之间转换 而且&#xff0c;inet_pton和inet_ntop这2个函数能够处理ipv4和ipv6。算是比较新的函数了。 inet_pton函数原型如下[将“点分十进制” &#xff0d;> “整数”] #include <sys/…

Firefox3 RC1颁布各种新特征发扬阐发更平定

作者: Dailon 出自: http://www.linuxdiyf.com Mozilla项目曾经颁布了Firefox 3 RC1。Firefox 3的新特征包罗对Javascript 1.8的支持、DOM和HTML的转变、微技俩&#xff08;microformats&#xff09;支持及一个扩展的Canvass完成。 Mozilla公司颠末对Javascript 1.8特征…