SunnyUI.FrameDecoder 流式数据解码库开源项目

我要开发同款
匿名用户2023年02月09日
77阅读
开发技术C#
所属分类网络工具包、程序开发
授权协议MIT

作品详情

SunnyUI.FrameDecoder是开源TCP、UDP、串口等流式数据的解码库。

开始从Nuget安装最新版本。

Install-PackageSunnyUI.FrameDecoder目的SunnyUI.FrameDecoder开源TCP、UDP、串口等流式数据解码库

实现解码自由底层缓冲区采用数据池实现通过使用池化缓冲区来消除大型对象堆分配减少GC次数缓冲区实现IBufferWrite接口广泛支持较新的内存相关类型,如Span<byte>, ReadOnlySpan<byte>以及Memory<byte>避免内存碎片提供出色的性能介绍TCP是面向连接的传输协议,TCP传输的数据是以流的形式,而流数据是没有明确的开始结尾边界,应用层处理接收数据时可能产生半包或者粘包,其主要原因如下:

TCP发送方原因:因为TCP本身传输的数据包大小就有限制,所以应用发出的消息包过大,TCP会把应用消息包拆分为多个TCP数据包发送出去。Negal算法的优化,当应用发送数据包太小,TCP为了减少网络请求次数的开销,它会等待多个消息包一起,打成一个TCP数据包一次发送出去。TCP接收方原因:因为TCP缓冲区里的数据都是字符流的形式,没有明确的边界,因为数据没边界,所以应用从TCP缓冲区中读取数据时就没办法指定一个或几个消息一起读,而只能选择一次读取多大的数据流,而这个数据流中就可能包含着某个消息包的一部分数据。所以为了解决半包或者粘包,得到应用层需要的数据,实现解码自由,开发了此数据解码库,原理也就是给数据流转时给流式数据加上消息边界。在接收数据时,将流式数据通过相应的解码器(FrameDecoder),解码输出完整的帧数据(FrameData)。

UDP是面向消息的,它有边界协议,可以根据消息的格式区分消息的开始和结尾。那为什么还要解码呢?举个例子,实际项目:FPGA通过千兆网卡将数据以UDP协议输出,其数据实际还是流式数据,需要在UDP接收到的数据中寻找包头和包尾,来截取一段需要的数据,这样数据解码器就有意义了。

串口在数据发送和接收时,根据串口的配置(波特率、奇偶校验等)、串口缓冲设置、数据发送间隔的不匹配,也会出现接收数据时可能产生半包或者粘包。Modbus-RTU总线是通过时间间隔来判断一帧数据结束的,3.5个字符时间内没有收到新的数据,则认为这一帧数据结束。普通的串口数据传输,还是要给数据增加消息边界,通过解码器来获取实际需要的数据。

其实不限于TCP、UDP、串口,只要是从流式数据中获取指定格式的数据,都可以用过解码器来实现。

有些网络库,例如:

Netty 有FrameDecoder;TouchSocket 有数据处理适配器;HP-Socket 则是通过Pack模式,在发送数据时加上消息边界。不一一列举,这些库主要是为了解决TCP数据的的解码。SunnyUI.FrameDecoder则面向流式数据,不拘泥于数据从哪儿来,通过流式数据的解码器来获取到有用的数据。

软件架构

流式数据有两种:

byte[]:字节数组string:字符串针对这两种数据,实现了泛型数据缓存: DataCache<T>,其内存分配通过数据池:DataPool<T> 实现通过DataCache<byte>实现字节数据组缓存,通过DataCache<char>实现字符串缓存

安装教程动态库应用环境:VS2012及以上均可,支持.NetFramework4.5+、包括.Net6、.Net7推荐通过Nuget安装:NuGet\Install-PackageSunnyUI.FrameDecoder或者通过Nuget搜索:SunnyUI.FrameDecoder安装。

使用说明字节数据帧解码器DelimiterBasedFrameDecoder基于分隔符-数据帧解码器数据格式: 构造函数:

///<summary>///构造函数///</summary>///<paramname="delimiters">分隔符,最好为多字节,并且数据中不会出现分隔符而造成误解码</param>///<paramname="maxFrameLength">最大数据长度,仅判断数据长度</param>publicDelimiterBasedFrameDecoder(byte[]delimiters,intmaxFrameLength=0) 示例:

varbts=newbyte[]{1,2,3,0xFF,0xFB};vardecoder1=newDelimiterBasedFrameDecoder(newbyte[]{0xFF,0xFB});decoder1.OnDecoder+=DelimiterBasedFrameDecoder_OnDecoder;decoder1.Decode(bts);privatestaticvoidDelimiterBasedFrameDecoder_OnDecoder(objectsender,IByteEventArgse){Console.WriteLine("Value:"+ByteHelper.HexString(e.Value));} 输出:

Value:010203 FixedLengthFrameDecoder固定长度-数据帧解码器数据格式: 构造函数:

///<summary>///构造函数///</summary>///<paramname="frameLength">帧固定长度</param>publicFixedLengthFrameDecoder(intframeLength) 示例:

varbts=newbyte[]{1,2,3,4,5,6,7,8};vardecoder0=newFixedLengthFrameDecoder(3);decoder0.OnDecoder+=FixedLengthFrameDecoder_OnDecoder;decoder0.Decode(bts);privatestaticvoidFixedLengthFrameDecoder_OnDecoder(objectsender,IByteEventArgse){Console.WriteLine("Value:"+ByteHelper.HexString(e.Value));} 输出:

Value:010203Value:040506 HeaderDelimiterFrameDecoder数据头部-数据帧解码器数据格式: 构造函数:

///<summary>///构造函数///</summary>///<paramname="headers">数据头部</param>///<paramname="maxFrameLength">最大数据长度,仅判断数据长度</param>publicHeaderDelimiterFrameDecoder(byte[]headers,intmaxFrameLength=0) 示例:

varbts=newbyte[]{0xFF,0xFB,1,2,3};vardecoder2=newHeaderDelimiterFrameDecoder(newbyte[]{0xFF,0xFB});decoder2.OnDecoder+=HeaderDelimiterFrameDecoder_OnDecoder;decoder2.Decode(bts);decoder2.Decode(bts);privatestaticvoidHeaderDelimiterFrameDecoder_OnDecoder(objectsender,IByteEventArgse){Console.WriteLine("Value:"+ByteHelper.HexString(e.Value));} 输出:

Value:010203 HeaderTagLengthValueTailFrameDecoder数据头部、标签、数据长度、数据、数据尾部-数据帧解码器数据格式: 构造函数:

///<summary>///构造函数///</summary>///<paramname="headers">数据头部</param>///<paramname="tails">数据尾部</param>///<paramname="tagLength">标签长度</param>///<paramname="valueLengthType">数据长度类型</param>///<paramname="valueIsLittleEndian">数据长度字节顺序</param>///<paramname="isFullLength">数据长度是否包含数据头部、标签、数据长度、数据尾部的长度,false为仅数据长度</param>///<paramname="maxFrameLength">最大数据长度,仅判断数据长度</param>publicHeaderTagLengthValueTailFrameDecoder(byte[]headers,byte[]tails,inttagLength,ValueLengthTypevalueLengthType,boolvalueIsLittleEndian=true,boolisFullLength=false,intmaxFrameLength=0) 示例:

varbts=newbyte[]{0xFF,0xFB,0xAA,2,3,4,0xF7,0xF7};vardecoder3=newHeaderTagLengthValueTailFrameDecoder(newbyte[]{0xFF,0xFB},newbyte[]{0xF7,0xF7},1,ValueLengthType.Byte);decoder3.OnDecoder+=HeaderTagLengthValueTailFrameDecoder_OnDecoder;decoder3.Decode(bts);privatestaticvoidHeaderTagLengthValueTailFrameDecoder_OnDecoder(objectsender,IByteEventArgse){varargs=(TagLengthValueFrameDataEventArgs)e;Console.WriteLine("Tag:"+ByteHelper.HexString(args.Tag)+",Value:"+ByteHelper.HexString(args.Value));} 输出:

Tag:AA,Value:0304 HeaderTailFrameDecoder数据头部、数据尾部-数据帧解码器数据格式: 构造函数:

///<summary>///构造函数///</summary>///<paramname="headers">数据头部</param>///<paramname="tails">数据尾部</param>///<paramname="maxFrameLength">最大数据长度,仅判断数据长度</param>publicHeaderTailFrameDecoder(byte[]headers,byte[]tails,intmaxFrameLength=0) 示例:

varbts=newbyte[]{0xFF,0xFB,2,3,4,0xF7,0xF7};vardecoder4=newHeaderTailFrameDecoder(newbyte[]{0xFF,0xFB},newbyte[]{0xF7,0xF7});decoder4.OnDecoder+=HeaderTailFrameDecoder_OnDecoder;decoder4.Decode(bts);privatestaticvoidHeaderTailFrameDecoder_OnDecoder(objectsender,IByteEventArgse){Console.WriteLine("Value:"+ByteHelper.HexString(e.Value));} 输出:

Value:020304 LengthValueFrameDecoder数据长度、数据-数据帧解码器数据格式: 构造函数:

///<summary>///构造函数///</summary>///<paramname="valueLengthType">数据长度类型</param>///<paramname="valueIsLittleEndian">数据长度字节顺序</param>///<paramname="isFullLength">数据长度是否包含数据长度的长度,false为仅数据长度</param>///<paramname="maxFrameLength">最大数据长度,仅判断数据长度</param>publicLengthValueFrameDecoder(ValueLengthTypevalueLengthType,boolvalueIsLittleEndian=true,boolisFullLength=false,intmaxFrameLength=0) 示例:

bts=newbyte[]{2,3,4};vardecoder5=newLengthValueFrameDecoder(ValueLengthType.Byte);decoder5.OnDecoder+=LengthValueFrameDecoder_OnDecoder;decoder5.Decode(bts);privatestaticvoidLengthValueFrameDecoder_OnDecoder(objectsender,IByteEventArgse){Console.WriteLine("Value:"+ByteHelper.HexString(e.Value));} 输出:

Value:0304 TagLengthValueFrameDecoder标签、数据长度、数据-数据帧解码器数据格式: 构造函数:

///<summary>///构造函数///</summary>///<paramname="tagLength">标签长度</param>///<paramname="valueLengthType">数据长度类型</param>///<paramname="valueIsLittleEndian">数据长度字节顺序</param>///<paramname="isFullLength">数据长度是否包含标签、数据长度的长度,false为仅数据长度</param>///<paramname="maxFrameLength">最大数据长度,仅判断数据长度</param>publicTagLengthValueFrameDecoder(inttagLength,ValueLengthTypevalueLengthType,boolvalueIsLittleEndian=true,boolisFullLength=false,intmaxFrameLength=0) 示例:

bts=newbyte[]{0xAA,2,3,4};vardecoder6=newTagLengthValueFrameDecoder(1,ValueLengthType.Byte);decoder6.OnDecoder+=TagLengthValueFrameDecoder_OnDecoder;decoder6.Decode(bts);privatestaticvoidTagLengthValueFrameDecoder_OnDecoder(objectsender,IByteEventArgse){varargs=(TagLengthValueFrameDataEventArgs)e;Console.WriteLine("Tag:"+ByteHelper.HexString(args.Tag)+",Value:"+ByteHelper.HexString(args.Value));} 输出:

Tag:AA,Value:0304 字符串解码器NMEA0183FrameDecoderNMEA0183-数据帧解码器数据格式: 示例:

vardecoder=newNMEA0183FrameDecoder();decoder.OnDecoder+=NMEA0183Decoder_OnDecoder;decoder.Decode("4,19.7,M,,,,0000*1F$GPGGA,092204.999,4250.5589,S,147");decoder.Decode("18.5084,E,1,04,24.4,19.7,M,,,,0000*1F$GPGSA,A,3,01,20,");decoder.Decode("19,13,,,,,,,,,40.4,24.4,32.2*0A$GPGSV,3,1,10,20,78,331,45,01,59,235,47,22,41,");decoder.Decode("069,,13,32,252,45*70$GPVTG,092204.999,42");publicstaticvoidNMEA0183Decoder_OnDecoder(objectsender,IStringEventArgse){Console.WriteLine(e.Value);} 输出:

$GPGGA,092204.999,4250.5589,S,14718.5084,E,1,04,24.4,19.7,M,,,,0000*1F$GPGSA,A,3,01,20,19,13,,,,,,,,,40.4,24.4,32.2*0A$GPGSV,3,1,10,20,78,331,45,01,59,235,47,22,41,069,,13,32,252,45*70 LineBasedFrameDecoder基于换行符-数据帧解码器数据格式: 示例:

vardecoder=newLineBasedFrameDecoder();decoder.OnDecoder+=NMEA0183Decoder_OnDecoder;decoder.Decode("*AA"+'\r'+'\n'+"$GPGGA");decoder.Decode("*1F"+'\n'+'\r'+"$GPGSA");decoder.Decode("*0A"+'\r'+"$GPGSV");decoder.Decode("*70"+'\n'+"$GPVTG");publicstaticvoidNMEA0183Decoder_OnDecoder(objectsender,IStringEventArgse){Console.WriteLine(e.Value);} 输出:

*AA$GPGGA*1F$GPGSA*0A$GPGSV*70 参与贡献Fork本仓库新建Feat_xxx分支提交代码新建PullRequest新的解码器如果有新的解码器建议,请添加Issue。

声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!
下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态

评论