Netty之ByteBuff

1、Jdk自带ByteBuffer

1.1、ByteBuffer简介

事实上,jdk自1.4版本,就已经提供了nio的ByteBuffer,用于在Java程序中操作原始数据。ByteBuffer可以用来读取和写入二进制数据,例如网络传输的数据、文件的内容等。

ByterBuffer的部分源代码如下

public abstract class ByteBufferextends Bufferimplements Comparable<ByteBuffer>
{// These fields are declared here rather than in Heap-X-Buffer in order to// reduce the number of virtual method invocations needed to access these// values, which is especially costly when coding small buffers.//final byte[] hb;                  // Non-null only for heap buffersfinal int offset;boolean isReadOnly;                 // Valid only for heap buffers// Creates a new buffer with the given mark, position, limit, capacity,// backing array, and array offset//ByteBuffer(int mark, int pos, int lim, int cap,   // package-privatebyte[] hb, int offset){super(mark, pos, lim, cap);this.hb = hb;this.offset = offset;}// Creates a new buffer with the given mark, position, limit, and capacity//ByteBuffer(int mark, int pos, int lim, int cap) { // package-privatethis(mark, pos, lim, cap, null, 0);}
}

从定义上看,它属于抽象类,不可直接实例化。它有两个非抽象子类,分别是:

  • HeapByteBuffer:在JVM的堆内存中创建的ByteBuffer对象。特点是可以快速分配和释放内存,但是读写性能相对较低,因为需要进行数据的复制。
  • DirectByteBuffer:操作系统的本地内存中创建的ByteBuffer对象。本地内存是直接在操作系统中分配的内存空间,对于大量的数据操作和网络传输等场景,DirectByteBuffer的读写性能相对较高。需要显式地调用System.gc()进行内存回收,否则可能会导致内存泄露。

1.2、ByteBuffer缺陷

ByteBuffer自身存在以下局限性:

1)长度一经初始化即固定,无法动态扩展。分配少了无法容纳大数据,分配多了浪费内存。

    public static void main(String[] args) {ByteBuffer buffer = ByteBuffer.allocate(10);buffer.putInt(1);buffer.putInt(2);buffer.putInt(3);System.out.println(buffer);//Exception in thread "main" java.nio.BufferOverflowException//at java.nio.Buffer.nextPutIndex(Buffer.java:532)//at java.nio.HeapByteBuffer.putInt(HeapByteBuffer.java:375)//at jforgame.demo.ByteBufferTest.main(ByteBufferTest.java:11)}

2)ByteBuffer只有一个标识位置的指针,读写不方便。

    public static void main(String[] args) {ByteBuffer buffer = ByteBuffer.allocate(10);buffer.put("jforgame".getBytes());// 需要flip()下,把limit设为position,position设为0buffer.flip();byte[] data = new byte[buffer.remaining()];buffer.get(data);String decoded = new String(data);System.out.println(decoded);}

2、Netty的ByteBuf

2.1、ByteBuf简介

类似的,ByteBuf也是一个抽象类,无法直接实例化。

public abstract class ByteBuf implements ReferenceCounted, Comparable<ByteBuf>, ByteBufConvertible {public ByteBuf() {}public abstract int capacity();public abstract ByteBuf capacity(int var1);public abstract int maxCapacity();public abstract ByteBufAllocator alloc();// 篇幅原因,省略其他方法
}

ByteBuf的子类非常复杂,这里作一个简要版

ByteBuf
|
+-- AbstractByteBuf|+-- PooledByteBuf|     ||     +-- PooledHeapByteBuf|     +-- PooledDirectByteBuf+-- UnpooledHeapByteBuf+-- UnpooledDirectByteBuf

ByteBuf不同子类实现原理不太一样,这里介绍ByteBuf基本功能

  • 内存管理:ByteBuf在内部维护了一个字节数组来存储数据,可以通过其他方式(如直接内存)创建ByteBuf来管理内存。

  • 读写操作:可以使用ByteBuf的read和write方法来读取和写入字节数据。这些方法支持基本的数据类型,如int、long、float、double等,以及字节数组、字符串等。

  • 索引操作:ByteBuf提供了readIndex和writeIndex两个指针,分别指示当前读取和写入的位置。可以使用相关方法来控制这些指针的位置,例如setIndex、readBytes、writeBytes等。

  • 顺序访问:ByteBuf提供了一系列顺序访问的方法,例如get、set、readBytes、writeBytes等。这些方法可以按照指定的顺序读取或写入字节数据。

  • 随机访问:ByteBuf还支持随机访问,可以通过set、get方法直接访问指定位置的字节数据。

  • 引用计数:ByteBuf使用引用计数来管理内存的释放。可以使用retain和release方法来增加和减少引用计数,当引用计数为0时,ByteBuf将会释放内存。

  • 缓冲区类型:ByteBuf有两种类型,HeapByteBuf和DirectByteBuf。HeapByteBuf使用JVM堆内存来存储数据,而DirectByteBuf使用直接内存存储数据。可以根据需求选择不同的类型。

2.2、ByteBuf自动扩容 

ByteBuf的初始大小,作用类似与ArrayList的构造函数,只是为了减少扩容的次数。

    public static void main(String[] args) {ByteBuf buffer = Unpooled.buffer(10);buffer.writeInt(1);buffer.writeInt(2);buffer.writeInt(3);System.out.println(buffer);}

每次写入的时候,会检测写入位置是否越界, 越界则扩展,扩展大小为下一个不小于最小容量的2的N次幂数值。

2.3、ByteBuf的读写位置分离 

Netty提供了两个指针变量,其中,readerIndex用于标示读取索引,writerIndex用于标示写入索引。这两个指针将ByteBuf分为三个区域,如下:

 discardableBytes | readableBytes | writableBytes | 
0             readerIndex        writerIndex     capacity    

当应用程序调用read操作时,从readerIndex开始读取。readerIndex到writerIndex之间的区域是可读区域,writerIndex到capacity的区域是可写入区域(动态扩展时会修改capacity)。0到readerIndex之间的区域是已经读取过的缓存区,可以调用disacardBytes操作来压缩空间,也可结合markPosition等API进行数据重读。

2.4、ByteBuf的Clear操作

Clear操作不清除缓存区数据,只是重置readerIndex和writerIndex的值。

 public static void main(String[] args) {ByteBuf buffer = Unpooled.buffer(10);buffer.writeInt(1);buffer.writeInt(2);// 重置读写索引buffer.clear();buffer.writeInt(3);buffer.writeInt(4);System.out.println(buffer.readInt());System.out.println(buffer.readInt());// 打印 3 4}

 2.5、ByteBuf的Mark和Reset操作

Mark操作用于备份数据,Reste操作用于回滚数据。由于ByteBuf有读写索引,相应的,Mark和Reset操作有4个方法,如下:

  • markReaderIndex:  ==> this.markedReaderIndex = this.readerIndex;
  • resetReaderIndex:  ==> this.readerIndex = this.markedReaderIndex;
  • markWriterIndex:  ==> this.markedWriterIndex = this.writerIndex;
  • resetWriterIndex:  ==> this.writerIndex = this.markedWriterIndex;

3、通信IO粘包拆包问题 

Tcp通信面向的是字节流,如同水管里的水,没有边界。因此,传输过程中会出现粘包(多个包融合在一起),拆包(一个包分成多个小包)问题。

很难解决吗,其实非常简单,也就几行代码的事!!

3.1使用ByteBuf相关API解决问题

假设我们的私有协议设计如下:

        // ----------------protocol pattern-------------------------// packetLength | cmd | body//    int         int   byte[]
  1. 解码器先读4个字节的长度,表示消息的字节数长度;若不足4个字节,则等待下一次字节流
  2. 读取到数据长度之后,假设为100,代表后面的消息(cmd+body)为100字节数
  3. 假设readerIndex到writerIndex直接的可读缓存区大于等于100,则读取到一个完整的消息
  4. 否则,回滚readerIndex,等待下一波字节流的到来
 @Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {if (in.readableBytes() < 4) {return;}in.markReaderIndex();// ----------------protocol pattern-------------------------// packetLength | cmd | body//    int         int   byte[]int length = in.readInt();if (length > maxProtocolBytes) {logger.error("message data frame [{}] too large, close session now", length);ctx.close();return;}if (in.readableBytes() < length) {in.resetReaderIndex();return;}int cmd = in.readInt();byte[] body = new byte[length - 4];in.readBytes(body);Class<?> msgClazz = messageFactory.getMessage(cmd);out.add(messageCodec.decode(msgClazz, body));}

总体来说,利用Netty的API,还是非常方便的处理半包读写问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/817207.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大数据】Apache Knox 概述

Apache Knox 概述 1.概述1.1 Kerberos 封装1.2 简化客户端证书的管理1.3 Apache Ranger 集成1.4 Hadoop URLs VS Knox URLs 2.自定义 Apache Knox2.1 Topology2.2 Provider2.3 Services2.4 Personalized services 3.Tips3.1 Setting up SSL3.2 常见问题3.2.1 Bulky answer3.2.2…

财务软件行业背景-易舟云

财税是每个企业的基本基石之一。财务报告讲述了公司的故事——它的利润和亏损、收益和债务、税收支出以及可用于未来增长的资产。随着信息时代的飞速发展&#xff0c;财务信息化建设日益完善&#xff0c;大量基于计算机网络的应用系统已经逐步深入财务管理领域。传统的会计录入…

过冲、振铃、非单调性

1、过冲&#xff08;Overshoot&#xff09;和振铃&#xff08;Ringing&#xff09;是电路中常见的信号失真现象&#xff0c;主要出现在开关电源、数字信号传输、通信系统以及其他涉及快速开关动作的电子设备中。它们通常与电路的瞬态响应有关&#xff0c;尤其是当电路受到阶跃输…

【学习笔记十三】EWM常见上架策略介绍

一、手工维护上架策略 系统不确定Storage type 和 bin&#xff0c;需要在创建仓库任务时或者确认仓库任务时手工输入仓位 1.后台配置-定义存储类型的类型0010 ①存储行为&#xff1a;标准仓位 ②入库规则&#xff1a;空仓未或添加至现有库存/空仓位 ③通用仓库任务&#x…

postgresql 备份恢复相关知识点整理归纳 —— 筑梦之路

概述 PG一般有两种备份方式&#xff1a;逻辑备份和物理备份 逻辑备份对于数据量大的场景下耗时较长&#xff0c;恢复也会耗时较长 物理备份拷贝文件的方式相对来说耗时较短&#xff0c;跟磁盘读写性能和网络传输性能有关 逻辑备份 pg_dump pg_dump 将表结构及数据以SQL语句…

微信小程序实现预约生成二维码

业务需求&#xff1a;点击预约按钮即可生成二维码凭码入校参观~ 一.创建页面 如下是博主自己写的wxml&#xff1a; <swiper indicator-dots indicator-color"white" indicator-active-color"blue" autoplay interval"2000" circular > &…

SpringBoot - Logback 打印第三方 Jar 日志解决方案

问题描述 最近碰到一个很苦恼的问题&#xff0c;就是第三方的 Jar 在自己项目里日志可以正常输出&#xff0c;但是一旦被引用到其他项目里&#xff0c;就日志死活打不出来…… 解决方案 这是原来的配置 - logback.xml <?xml version"1.0" encoding"UTF-8…

LigaAI x 极狐GitLab,共探 AI 时代研发提效新范式

近日&#xff0c;LigaAI 和极狐GitLab 宣布合作&#xff0c;双方将一起探索 AI 时代的研发效能新范式&#xff0c;提供 AI 赋能的一站式研发效能解决方案&#xff0c;让 AI 成为中国程序员和企业发展的新质生产力。 软件研发是一个涉及人员多、流程多、系统多的复杂工程&#…

基于 Operator 部署 Prometheus 监控 k8s 集群

目录 一、环境准备 1.1 选择版本 1.2 过滤镜像 1.3 修改 yaml 镜像 1.4 移动 *networkPolicy*.yaml 1.5 修改 service 文件 1.6 提前下载镜像并推送到私有镜像仓库 1.7 修改镜像&#xff08;可选&#xff09; 二、执行创建 三、查看 pod 状态 四、访问 prometheus、…

Ceph [OSDI‘06]论文阅读笔记

原论文&#xff1a;Ceph: A Scalable, High-Performance Distributed File System (OSDI’06) Ceph简介及关键技术要点 Ceph是一个高性能、可扩展的分布式文件系统&#xff0c;旨在提供出色的性能、可靠性和可扩展性。为了最大化数据和元数据管理的分离&#xff0c;它使用了一…

2024年第十五届蓝桥杯C/C++B组复盘(持续更新)

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 试题A&#xff1a;握手问题问题描述思路 试题B&#xff1a;小球反弹问题描述思路…

一个令人惊艳的图片高清化重绘神器:SUPIR来了!

今天给大家分享一个将模糊图片还原为照片级高清图像的AI项目&#xff1a;SUPIR。这个项目以尖端的大规模人工智能革新图像恢复技术&#xff0c;通过文本驱动、智能修复&#xff0c;将AI技术与创新思维相结合&#xff0c;赋予每张图像全新的生命力。这个项目的修复能力本质上是一…

AI的说服力如人类?Anthropic最新研究揭秘机器的辩论能力|TodayAI

人们常常对人工智能模型在对话中的说服力表现持怀疑态度。长久以来&#xff0c;社会上一直存在一个疑问&#xff1a;人工智能是否会达到人类那样&#xff0c;在对话中具有改变他人想法的能力&#xff1f; 直到最近&#xff0c;这一领域的实证研究相对有限&#xff0c;对于人工…

零基础使用FlexLua打造LoRa无线气体流量计,硬件轻松快速开发。

在工业领域&#xff0c;对气体流量进行准确监测和管理是保障生产安全和提高效率的重要环节。而LoRa&#xff08;长距离低功耗无线技术&#xff09;作为一种适用于远距离、低功耗的通信技术&#xff0c;为无线传感器网络的建设提供了可靠的解决方案。结合气体流量传感技术&#…

畅游网络:构建C++网络爬虫的指南

概述 随着信息时代的来临&#xff0c;网络爬虫技术成为数据采集和网络分析的重要工具。本文旨在探讨如何运用C语言及其强大的cpprestsdk库构建一个高效的网络爬虫&#xff0c;以便捕捉知乎等热点信息。为了应对IP限制的挑战&#xff0c;我们将引入亿牛云爬虫代理服务&#xff…

NPU流式输出-torch_npu和transformers框架-多线程Streamer-昇腾910B-EE1001

前情提要 torch_npu框架不支持多线程自动set_device 报错详情 直接使用transformers的TextIteratorStreamer进行流式推理&#xff0c;会报错 Exception in thread Thread-6: Traceback (most recent call last):File "/root/anaconda3/envs/AI/lib/python3.9/threadin…

《springcloud alibaba》 六 微服务链路跟踪skywalking

目录 准备调整配置接入多个微服务网关项目调整order-seata项目stock-seata项目测试 接入网关微服务 skywalking持续化到mysql自定义链路跟踪pom .xmlorderControllerOrderServiceOrderDaoOrderTblMapper.xml测试 性能剖析日志tid打印pom.xmllogback-spring.xml日志收集启动项目…

OSI七层网络模型 —— 筑梦之路

在信息技术领域&#xff0c;OSI七层模型是一个经典的网络通信框架&#xff0c;它将网络通信分为七个层次&#xff0c;每一层都有其独特的功能和作用。为了帮助记忆这七个层次&#xff0c;有一个巧妙的方法&#xff1a;将每个层次的英文单词首字母组合起来&#xff0c;形成了一句…

TensorFlow-GPU安装

第一步&#xff1a;安装Anaconda、cuda以及对应的cudNN&#xff0c;其中TensorFlow-GPU对应版本如下图所示&#xff1a; 想看最新的话&#xff0c;可以看官方链接&#xff1a;https://www.tensorflow.org/install/source_windows?hlzh-cn 第二步&#xff1a;创建对应的虚拟环…

在Windows上安装Go编译器并配置Golang开发环境

文章目录 1、安装Go语言编译程序1.1、下载GoLang编译器1.2、安装GoLang编译器 2、配置Golang IDE运行环境2.1、配置GO编译器2.1.1、GOROOT 概述2.1.2、GOROOT 作用2.1.2、配置 GOROOT 2.2、配置GO依赖管理2.2.1、Module管理依赖2.2.2、GOPATH 管理依赖 2.3、运行GO程序2.3.1、创…