DotNetty ByteBuffer

news2024/11/25 4:19:04

DotNetty是一个高性能的.NET网络通信框架,基于Netty,支持TCP、UDP、HTTP、WebSocket等协议。适用于高并发、低延迟场景,如实时通信、游戏服务器、IoT应用及大型分布式系统,通过异步I/O、零拷贝等技术提升性能,具备易用性、可扩展性。
架构上,围绕Channel、EventLoop、ChannelPipeline、ChannelHandlerContext设计,包含Transport、Codec、Handler等模块,简化网络编程,加速数据传输处理。

ByteBuffer 用于高效处理字节数据,固定容量,通过allocate或wrap创建。涉及position和limit追踪读写位置,提供get/put等读写方法,flip切换读写模式,clear清空缓冲区,compact移动数据并准备下一轮读写,适用于高性能IO与网络通信。.

优点
零拷贝通过复合缓冲区实现。
动态容量增长。
无需flip切换读写模式。
分离读写索引。
内置引用计数。
支持缓冲区池化。
优化网络通信中的字节处理。

结构
readerIndex 读取,随读增。
writerIndex 写入,随写增。
capacity容量。
在这里插入图片描述
ByteBuffer属性
readIndex:下一个读位
writeIndex:下一个写位置
capacity:容量
0:缓冲区开始位置

已经读取的区域:[0,readerindex)
可读取的区域:[readerindex,writerIndex)
可写的区域: [writerIndex,capacity)
读写独立索引,操作命名区分(read/write自动进,get/set不影响索引)。
支持设定最大容量,超限写操作将抛异常,默认上限Integer.MAX_VALUE。
readerIndex writerIndex 本质为灵活高效字节容器

堆缓冲区
最常用的 ByteBuffer 模式是将数据存储在堆空间中。这种模式被称为支撑数组(backing array),它能在没有使用池化的情况下提供快速的分配和释放。可以由 hasArray() 来判断检查 ByteBuffer是否由数组支撑。如果不是,则这是一个直接缓冲区。

直接缓冲区
直接缓冲区是另外一种 ByteBuffer 模式。
直接缓冲区的主要缺点是,相对于基于堆的缓冲区,它们的分配和释放都较为昂贵。

复合缓冲区
复合缓冲区 CompositeByteBuf,它为多个 ByteBuffer提供一个聚合视图。比如 HTTP 协议, 分为消息头和消息体,这两部分可能由应用程序的不同模块产生,各有各的 ByteBuffer,将会在消息被发送的时候组装为一个 ByteBuffer,此时可以将这两个 ByteBuffer聚合为一个 CompositeByteBuf,然后使用统一和通用的 ByteBuffer API 来操作。

如何在的程序中获得 ByteBuf 的实例,并使用它呢?Netty 提供了两种方式

ByteBufAllocator 接口
ByteBufAllocator 分配任意类型的 ByteBuffer 实例。

buffer(): 基于堆/直接内存ByteBuffer。
heapBuffer(): 仅堆内存。
directBuffer(): 仅直接内存。
compositeBuffer(): 可组合多个缓冲区,支持堆/直接内存。
ioBuffer(): 适配I/O操作,优先直接内存(需Unsafe支持)。
ByteBufAllocator:
Channel ChannelHandlerContext

Unpooled 缓冲区

Unpooled工具类助创ByteBuffer
buffer():堆内存ByteBuffer
directBuffer():直接内存ByteBuffer
wrappedBuffer():包装数据的ByteBuffer
copiedBuffer():复制数据的ByteBuffer 适用范围广泛,不仅限于Netty网络项目。

 IByteBuffer byteBuf = Unpooled.CopiedBuffer("hello,world!", Encoding.UTF8); 

ByteBuf访问/读写
索引从0开始至capacity()-1。
随机访问(get/set)不改索引,需显式调用readerIndex()/writerIndex()移动。
顺序访问分两类:
get/set:固定索引,读写数据不移位。
read/write:自动调整readerIndex/writerIndex。

isReadable() 如果至少有一个字节可供读取,则返回 true
isWritable() 如果至少有一个字节可被写入,则返回 true
readableBytes() 返回可被读取的字节数
writableBytes() 返回可被写入的字节数
capacity() 返回 ByteBuffer 可容纳的字节数。在此之后,它会尝试再次扩展直到达到
maxCapacity()
maxCapacity() 返回 ByteBuffer 可以容纳的最大字节数
hasArray() 如果 ByteBuffer 由一个字节数组支撑,则返回 true
array() 如果 ByteBuffer 由一个字节数组支撑则返回该数组

可丢弃字节
读操作后,字节积累在"可丢弃"段,始于readerIndex。
discardReadBytes()释放已读字节,回收空间,可能导致之前数据移动。
此操作可能涉及内存复制,谨慎使用。

在这里插入图片描述

可读字节:存储实际数据,新缓冲区默认从readerIndex=0开始。
可写字节:空白区域待写入,新缓冲区writerIndex初设0,写操作后自动递增。
在这里插入图片描述

资源释放
处理Netty入站ByteBuffer ,可选自动释放:用SimpleChannelInboundHandler,或在channelRead()末手动调用ReferenceCountUtil.release(msg)确保资源管理。

using DotNetty.Buffers;
using DotNetty.Transport.Channels;

public class CommanChannelInboundHandler : SimpleChannelInboundHandler<object>
{
    protected override void ChannelRead(IChannelHandlerContext context, object message)
    {
        bool shouldRelease = true;

        try
        {
            if (IsMessageAcceptable(message))
            {
                ChannelRead0(context, message);
            }
            else
            {
                shouldRelease = false;
                context.FireChannelRead(message);
            }
        }
        finally
        {
            if (AutoRelease && shouldRelease)
            {
                ResourceUtil.Release(message);
            }
        }
    }

    private bool IsMessageAcceptable(object msg)
    {
       
        return msg is IByteBuffer; // 假设只处理IByteBuffer类型的消息
    }

    protected virtual void ChannelRead0(IChannelHandlerContext context, object message)
    {
        //IByteBuffer ...
    }

   
    private bool AutoRelease { get; set; } = true;
}

对于出站请求,不管 ByteBuffer 是否由我们的业务创建的,当调用了 write 或者 writeAndFlush 方法后,Netty 会自动替我们释放,不需要我们业务代码自行释放。

   // 创建ByteBuf对象,初始容量为1,内部动态扩容以容纳更多数据
   IByteBuffer byteBuf = Unpooled.Buffer(1);
   Console.WriteLine("byteBuf=" + byteBuf);

   for (int i = 0; i < 8; i++)
   {
       byteBuf.WriteByte(i);
   }
   Console.WriteLine("byteBuf=" + byteBuf);

   for (int i = 0; i < 5; i++)
   {
       Console.WriteLine(byteBuf.GetByte(i));
   }
   Console.WriteLine("byteBuf=" + byteBuf);

   for (int i = 0; i < 5; i++)
   {
       Console.WriteLine(byteBuf.ReadByte());
   }
   Console.WriteLine("byteBuf=" + byteBuf);

   //byteBuf2
   // 使用Unpooled工具类创建ByteBuf,内容为"hello,world!"
   IByteBuffer byteBuf2 = Unpooled.CopiedBuffer("hello,world!", Encoding.UTF8); // Unpooled.CopiedBuffer("hello,world!", Encoding.UTF8);
   // 使用相关的方法
   if (byteBuf2.HasArray) // if (byteBuf2.HasArray)
   {
       byte[] content = byteBuf2.Array;
       // 将content转成字符串
       Console.WriteLine(Encoding.UTF8.GetString(content));
       Console.WriteLine("byteBuf2=" + byteBuf2);

       Console.WriteLine(byteBuf2.GetByte(0)); // 获取数组0这个位置的字符'h'的ASCII码,h=104

       int len = byteBuf2.ReadableBytes; // 可读的字节数 12
       Console.WriteLine("len=" + len);

       // 使用for取出各个字节并转换为对应的字符打印
       for (int i = 0; i < len; i++)
       {
           Console.WriteLine((char)byteBuf2.GetByte(i));
       }

       // 范围读取
       Console.WriteLine(byteBuf2.GetCharSequence(0, 6, Encoding.UTF8));
       Console.WriteLine(byteBuf2.GetCharSequence(6, 6, Encoding.UTF8));
   }


   //byteBuf3 WrappedBuffer
   var str1 = Encoding.UTF8.GetBytes("hello,world!");
   var byteBuf3 = Unpooled.WrappedBuffer(str1);
   if (byteBuf3.HasArray) // if (byteBuf2.HasArray)
   {
       byte[] content = byteBuf3.Array;
       // 将content转成字符串
       Console.WriteLine(Encoding.UTF8.GetString(content));
       Console.WriteLine("byteBuf3=" + byteBuf3);

       Console.WriteLine(byteBuf3.GetByte(0)); // 获取数组0这个位置的字符'h'的ASCII码,h=104

       int len = byteBuf3.ReadableBytes; // 可读的字节数 12
       Console.WriteLine("len=" + len);

       // 使用for取出各个字节并转换为对应的字符打印
       for (int i = 0; i < len; i++)
       {
           Console.WriteLine((char)byteBuf3.GetByte(i));
       }

       // 范围读取
       Console.WriteLine(byteBuf3.GetCharSequence(0, 6, Encoding.UTF8));
       Console.WriteLine(byteBuf3.GetCharSequence(6, 6, Encoding.UTF8));
   }

结果得出 get操作 readerIndex 不变,read操作使其移动。

End

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

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

相关文章

eNSP小练习一枚

问答看到的&#xff0c;随便敲了敲&#xff0c;希望各路大佬不吝赐教~ 话说现在的问答全是ai&#xff0c;乌烟瘴气的 首先配置全互通&#xff0c;ip vlan 端口隔离 ospf啥的 SWA # vlan batch 10 20 30 99 # interface Vlanif1ip address 10.1.1.2 255.255.255.0 # interf…

【ETAS CP AUTOSAR工具链】ARXML文件详解

本篇文章首先对ARXML这种文件格式做了一个概述&#xff0c;叙述了这种标签语言的基本语法&#xff08;如果您用HTML做过网页&#xff0c;那么这种格式您一定不会陌生&#xff09;&#xff0c;然后对ARXML文件都会包含的一些基本信息做了详细的解读&#xff0c;最后基于使用ISOL…

[数据集][目标检测]吸烟检测数据集VOC+YOLO格式1449张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1449 标注数量(xml文件个数)&#xff1a;1449 标注数量(txt文件个数)&#xff1a;1449 标注…

鸿蒙开发配置官方地图

一共需要配置 p12 p7b cer csr 四个文件 p12文件配置 注意创建文件名必须是.p12 到AGC创建项目 AppGallery Connect 添加自己的项目名称 我没有开启 暂时不需要 看个人需求 下载刚创建的cer证书 回到我的项目中 点击刚创建的项目 点击这里 四个文件齐全了 "metadata&qu…

近临算法(个人总结版)

背景 近邻算法&#xff08;Nearest Neighbor Algorithm&#xff09;是一种基本但非常有效的分类和回归方法。最早由Fix和Hodges在1951年提出&#xff0c;经过几十年的发展和改进&#xff0c;已成为数据挖掘、模式识别和机器学习领域的重要工具。近邻算法基于相似性原则&#x…

DVWA登录页面空白问题解决

问题&#xff1a; 创建完成后打开登录页面&#xff0c;发现打不开&#xff0c;一片空白 解决&#xff1a; php版本不对&#xff0c;更换版本即可

VueHooks Plus:Vue 3 Hooks 的全面解决方案

VueHooks Plus&#xff1a;Vue 3 Hooks 的全面解决方案 文章目录 VueHooks Plus&#xff1a;Vue 3 Hooks 的全面解决方案〇、元信息一、概述快速开始TypeScript 支持交互式 Demo 演示服务器端渲染&#xff08;SSR&#xff09;支持基于插件模式的请求函数按需加载安全性和测试 二…

PHP生成二维码+二维码包含logo图片展示

composer require chillerlan/php-qrcode 用到的扩展自己安装&#xff08;注&#xff1a;只生成二维码只要开gd扩展就行&#xff09; 仅生成二维码看这个&#xff1a; use chillerlan\QRCode\QRCode;public function QRCode(){$qrcode new QRCode();$url "http://ww…

如何利用51建模网,实现3D模型线上展示和应用?

按照下面的步骤&#xff0c;在51建模网上传3D模型&#xff0c;并编辑完成后&#xff0c;接下来就是如何让这些3D模型得到更好的展示、传播和应用。 一、3D内容快速分享与传播 3D模型在51建模网上传发布后&#xff0c;即可获得一个可分享的链接和二维码&#xff0c;直接分享给客…

jenkins插件之Warnings

Warnings插件&#xff0c;收集静态分析工具报告的编译器警告或问题&#xff0c;并将结果可视化。它内置了对许多编译器的支持&#xff08;cpp&#xff0c;clang&#xff0c;java等&#xff09;和工具&#xff08;spotbugs&#xff0c;pmd&#xff0c;checkstyle&#xff0c;esl…

力扣226. 翻转二叉树(DFS的两种思路)

Problem: 226. 翻转二叉树 文章目录 题目描述思路复杂度Code 题目描述 思路 涉及二叉树的递归解法时往往需要考虑两种思路&#xff1a; 1.在递归遍历时执行题目需要的具体要求&#xff1b; 2.将一个大问题分解为多个小子问题 具体到本体&#xff1a; 思路1&#xff1a;遍历 先…

作业-day-240521

多点思维导图 面试题 1、项目中如何实现TCP的并发 1&#xff09;、一般的TCP服务器通信&#xff0c;只能完成一个客户端的操作。要实现多客户端的通信&#xff0c;可使服务器端循环创建并收发客户端的通信。 2&#xff09;、但仅循环服务器使用的情况&#xff0c;由于accept…

股指期权和股指期货的区别

今天期权懂带你了解股指期权和股指期货的区别。在金融衍生品市场&#xff0c;既有股指期货又有股指期权&#xff0c;期货与期权是两种不同的资产。 股指期权和股指期货的区别 权利与义务&#xff1a; 股指期货是一种协议&#xff0c;买卖双方都有义务在合约到期时按照约定的价…

CSS demo演示 20240524

说明&#xff1a;不修改父盒子的样式&#xff0c;只在子盒子上设置定位&#xff0c;让子盒子定位在父盒子右侧。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title><style>…

CGAN|生成手势图像|可控制生成

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章&#xff1a;TensorFlow入门实战&#xff5c;第3周&#xff1a;天气识别&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 CGAN&#xff08;条件生成对抗网络&#xf…

项目十二:简单的python基础爬虫训练

许久未见&#xff0c;甚是想念&#xff0c;今日好运&#xff0c;为你带好运。ok&#xff0c;废话不多说&#xff0c;希望这门案例能带你直接快速了解并运用。&#x1f381;&#x1f496; 基础流程 第一步&#xff1a;安装需要用到的requests库&#xff0c;命令如下 pip inst…

Vue3实战笔记(41)—自己封装一个计时器Hooks

文章目录 前言计时器钩子总结 前言 在Vue项目中&#xff0c;封装一个计时器挂钩&#xff08;Hook&#xff09;是一种实用的技术&#xff0c;它允许你在组件中方便地管理定时任务&#xff0c;如倒计时、计时器等&#xff0c;而无需在每个使用场景重复编写相同的逻辑代码。 计时…

uniapp如何使用自定义的图标

http://t.csdnimg.cn/8KenC 以上是原文章,下面内容是从这篇文章转发的 一、导入 1.在官方&#xff08;iconfont-阿里巴巴矢量图标库&#xff09;选择自己想要的图标&#xff0c;加入购物车 2. 在点击购物车下载代码 3.解压文件夹 并更改名字 4.将文件夹&#xff08;iconfont&…

Xline社区会议Call Up|在 CURP 算法中实现联合共识的安全性

为了更全面地向大家介绍Xline的进展&#xff0c;同时促进Xline社区的发展&#xff0c;我们将于2024年5月31日北京时间11:00 p.m.召开Xline社区会议。 欢迎您届时登陆zoom观看直播&#xff0c;或点击“阅读原文”链接加入会议&#xff1a; 会议号: 832 1086 6737 密码: 41125…

软件开发成本估算 5大注意事项

一般来说&#xff0c;软件开发成本估算分为&#xff1a;软件规模估算、工作量估算、成本估算和确定软件开发成本等四个过程&#xff0c;其估算基本流程如下&#xff1a; 软件开发成本估算流程 为了进一步确保估算的准确性&#xff0c;提高资源规划和分配效率&#xff0c;确保软…