C# 设计一个可变长度的数据通信协议编码和解码代码。

设计一个可变长度的数据通信协议编码和解码代码。
要有本机ID字段,远端设备ID字段,指令类型字段,数据体字段,校验字段。其中一个要求是,每次固定收发八个字节,单个数据帧超过八个字节需要分包收发。对接收的数据帧要先存入环形缓存区,解码函数需要对环形缓存区中的协议数据持续解码,直到没有数据。解析出的数据最后逐个列出来,验证对错。对于存在的丢包问题,要求有重发机制。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace edcode_s
{/** Packet 类表示一个数据包,* 包含本地ID、远程ID、命令类型、数据长度和数据内容等字段。*/class Packet{public byte LocalID;public byte RemoteID;public byte CommandType;public byte DataLength;public byte[] Data = new byte[255];public ushort CRC;}/** RingBuffer 类实现了一个环形缓冲区,* 用于存储发送和接收的数据。* 它有一个固定大小的缓冲区,* 通过添加和读取操作来管理数据。*/class RingBuffer{private const int BufferSize = 1024;private byte[] buffer = new byte[BufferSize];private int start = 0;private int end = 0;/** Add方法* 将给定的字节数组data中的数据按顺序添加到循环缓冲区中,* 直到填满整个缓冲区或达到指定的length长度。*/public void Add(byte[] data, int length){for (int i = 0; i < length; i++){buffer[end] = data[i];end = (end + 1) % BufferSize;}}/** Read方法* 从循环缓冲区中读取指定长度的数据,* 并将其存储到给定的字节数组中,* 从指定的偏移量开始存储。* 如果没有读取到任何数据(即缓冲区为空),* 则返回0;否则返回1表示成功读取了数据。*/public int Read(byte[] data, int offset, int length){if (IsEmpty())return 0;for (int i = 0; i < length; i++){data[offset + i] = buffer[start];start = (start + 1) % BufferSize;}return 1;}public bool IsEmpty(){return start == end;}}/** Protocol 类是通信协议的核心部分,* 负责发送和接收数据包。* 它使用 RingBuffer 来存储发送和接收的数据。*/class Protocol{private const int PacketSize = 8;private RingBuffer ringBuffer = new RingBuffer();private Random rand = new Random();/** SendPacket 方法将一个 Packet 对象转换为字节数组,并计算CRC校验码,* 然后将数据分块发送到缓冲区中。* 如果模拟了数据包丢失的情况,则会重新发送数据包。* */public void SendPacket(Packet packet){int totalLength = 4 + packet.DataLength + 2;    byte[] buffer = new byte[totalLength];buffer[0] = packet.LocalID;buffer[1] = packet.RemoteID;buffer[2] = packet.CommandType;buffer[3] = packet.DataLength;Array.Copy(packet.Data, 0, buffer, 4, packet.DataLength);ushort crc = ComputeCRC(buffer, totalLength - 2);//变量crc转换为字节数组,并将该字节数组复制到buffer字节数组中。//totalLength - 2 表示从 buffer 数组的索引位置 totalLength - 2 开始粘贴数据BitConverter.GetBytes(crc).CopyTo(buffer, totalLength - 2);for (int i = 0; i < totalLength; i += PacketSize){int chunkSize = Math.Min(PacketSize, totalLength - i);byte[] chunk = new byte[chunkSize];Array.Copy(buffer, i, chunk, 0, chunkSize);if (!SimulatePacketLoss(0.1f)) // 10% packet loss rate{ringBuffer.Add(chunk, chunkSize);}else{Console.WriteLine("Packet loss occurred, resending...");ResendPacket(chunk, chunkSize);}}}/** DecodePacket 方法从缓冲区中读取数据,* 解析出数据包的各个字段,* 并进行CRC校验。如果校验成功,则返回 true,否则返回 false。*/public bool DecodePacket(out Packet packet){packet = new Packet();if (ringBuffer.IsEmpty())return false;byte[] header = new byte[4];ringBuffer.Read(header, 0, 4);packet.LocalID = header[0];packet.RemoteID = header[1];packet.CommandType = header[2];packet.DataLength = header[3];packet.Data = new byte[packet.DataLength];ringBuffer.Read(packet.Data, 0, packet.DataLength);ushort receivedCRC;byte[] crcBytes = new byte[2];ringBuffer.Read(crcBytes, 0, 2);receivedCRC = BitConverter.ToUInt16(crcBytes, 0);byte[] fullPacket = new byte[4 + packet.DataLength];Array.Copy(header, 0, fullPacket, 0, 4);//将一个数组packet.Data的从0位置开始的长度为packet.DataLength的内容复制到另一个数组fullPacket的4位置。Array.Copy(packet.Data, 0, fullPacket, 4, packet.DataLength);ushort computedCRC = ComputeCRC(fullPacket, fullPacket.Length);if (receivedCRC != computedCRC){Console.WriteLine("CRC error");return false;}return true;}/** ResendPacket 方法将数据包重新添加到缓冲区中,以便重新发送。*/private void ResendPacket(byte[] data, int length){ringBuffer.Add(data, length);}/** SimulatePacketLoss 方法根据给定的丢包率随机决定是否模拟数据包丢失。*/private bool SimulatePacketLoss(float lossRate){return rand.NextDouble() < lossRate;//生成一个0到1之间的随机小数,并将其与lossRate进行比较。}/** ComputeCRC 方法计算给定数据的CRC校验码(CRC-16)。*/private ushort ComputeCRC(byte[] data, int length){/** 变量crc初始化为0xFFFF。然后使用两个嵌套的循环来遍历数据并计算CRC值。* 外层循环遍历整个数据数组,内层循环处理每个字节的每一位。* 在内层循环中,首先检查crc的最低位是否为1。* 如果是1,则将crc右移一位并与0xA001进行异或操作;* 否则,直接将crc右移一位。*///CRC寄存器被初始化0xFFFF。ushort crc = 0xFFFF;for (int i = 0; i < length; i++){//将数据的第一个字节(8位)与CRC寄存器的当前值进行异或运算,并将结果存回CRC寄存器。crc ^= data[i];//根据最低有效位(LSB)是否为0来决定下一步操作。//如果LSB为0,则直接将CRC寄存器的内容右移一位;//如果LSB为1,则在右移一位后,//还需要与一个特定的16位多项式(如0xA001)进行异或运算。for (int j = 0; j < 8; j++){if ((crc & 1) != 0)crc = (ushort)((crc >> 1) ^ 0xA001);elsecrc >>= 1;}}return crc;}}/** Program 类是程序的入口点,创建一个 Protocol 对象,* 构造一个 Packet 对象,然后发送该数据包,* 并尝试解码接收到的数据包。*/class Program{static void Main(string[] args){Protocol protocol = new Protocol();Packet packet = new Packet();packet.LocalID = 1;packet.RemoteID = 2;packet.CommandType = 0x01;packet.Data = new byte[] { 0x11, 0x22, 0x33, 0x44, 0x55,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xaa,0xbb,0xff };packet.DataLength = byte.Parse(packet.Data.Length.ToString());protocol.SendPacket(packet);if (protocol.DecodePacket(out Packet received)){Console.WriteLine("Packet received successfully:");Console.WriteLine($"Local ID: {received.LocalID}");Console.WriteLine($"Remote ID: {received.RemoteID}");Console.WriteLine($"Command Type: {received.CommandType:X2}");Console.WriteLine($"Data Length: {received.DataLength}");Console.Write("Data: ");for (int i = 0; i < received.DataLength; i++){Console.Write($"{received.Data[i]:X2} ");}Console.WriteLine();}else{Console.WriteLine("Failed to decode packet or CRC error occurred.");}Console.ReadKey();}}}

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

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

相关文章

超详细信息收集篇

1 域名信息收集 1.1 域名是什么 域名&#xff08;英语&#xff1a;Domain Name&#xff09;&#xff0c;又称网域&#xff0c;是由一串用点分隔的名字组成的 Internet 上某一台 计算机 或计算机组的名称&#xff0c;用于在数据传输时对计算机的定位标识&#xff08;有时也指地…

数据结构——栈和队列(C语言实现)

写在前面&#xff1a; 栈和队列是两种重要的线性结构。其也属于线性表&#xff0c;只是操作受限&#xff0c;本节主要讨论的是栈和队列的定义、表示方法以及C语言实现。 一、栈和队列的定义与特点 栈&#xff1a;是限定仅在表尾进行插入和删除的线性表。对栈来说&#xff0c;表…

【经验分享】关于静态分析工具排查 Bug 的方法

文章目录 编译器的静态分析cppcheck安装 cppcheck运行 cppcheck 程序员的日常工作&#xff0c;不是摸鱼扯皮&#xff0c;就是在写 Bug。虽然这是一个梗&#xff0c;但也可以看出&#xff0c;程序员的日常一定绕不开 Bug。而花更少的时间修复软件中的 Bug&#xff0c;且不引入新…

C#自定义异常(Exception)的实现

1、自定义异常类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace ExceptionApp {public class CustomException:Exception{//默认构造函数public CustomException():base() { }//接收错误信…

leetcode hot 100 刷题记录(medium)

题目3&#xff1a;无重复字符的最长子串&#xff08;YES&#xff09; 解题思路&#xff1a;其实最好想到的方法就是使用两层for,让每个字符都可以是子串的首字符&#xff0c;查看哪个子串的长度最长即可。 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长 子…

lightgbm

lightGBM 1.sklearn 使用代码 【机器学习基础】XGBoost、LightGBM与CatBoost算法对比与调参 首先&#xff0c;XGBoost、LightGBM和CatBoost都是目前经典的SOTA&#xff08;state of the art&#xff09;Boosting算法&#xff0c;都可以归类到梯度提升决策树算法系列。三个模…

探索LangChain的单元测试世界:主流框架全解析

探索LangChain的单元测试世界&#xff1a;主流框架全解析 引言 在软件开发过程中&#xff0c;单元测试是确保代码质量的关键环节。LangChain作为一个多语言编程工具链&#xff0c;支持多种编程语言&#xff0c;每种语言都有其对应的单元测试框架。本文将详细介绍LangChain支持…

5. JavaSE ——【适合小白的数组练习题】

&#x1f4d6;开场白 亲爱的读者&#xff0c;大家好&#xff01;我是一名正在学习编程的高校生。在这个博客里&#xff0c;我将和大家一起探讨编程技巧、分享实用工具&#xff0c;并交流学习心得。希望通过我的博客&#xff0c;你能学到有用的知识&#xff0c;提高自己的技能&a…

【区块链 + 智慧政务】澳门:智慧城市建设之证书电子化项目 | FISCO BCOS应用案例

2019 年 2 月 27 日&#xff0c;澳门政府设立的澳门科学技术发展基金与微众银行达成合作&#xff0c;通过区块链、人工智能、大数据、 云计算等创新技术&#xff0c;共同推进澳门特区的智慧城市建设与未来型城市发展&#xff0c;提升粤港澳大湾区的科创能力。在澳 门智慧城市建…

【数学建模】高温作业专用服装设计(2018A)隐式差分推导

为方便计算&#xff0c;对区域进行离散化处理&#xff0c;采用隐式差分格式进行离散计算。隐式差分格式如图&#xff1a; 每层材料内部 对第 j j j层材料: 其中&#xff0c; λ j \lambda_j λj​表示第 j j j层的热扩散率&#xff0c; c j c_j cj​表示第 j j j层的比热容…

Matplotlib库学习之pyplot.figure()函数

Matplotlib库学习之pyplot.figure()函数 一、简介 pyplot.figure() 是 Matplotlib 的 pyplot 模块中的一个函数&#xff0c;用于创建一个新的图形&#xff08;figure&#xff09;。在 Matplotlib 中&#xff0c;图形是绘图元素的容器&#xff0c;可以包含多个坐标轴&#xff…

linux需要熟悉的命令理解记忆

(1)光标插入 (1)一般模式下: i 插入到光标前方 记忆方法:在一般模式下, 光标选中字符, 我们按下 i, 就会插入光标的前方, insert, 表示插队 (2)一般模式下: a 插入到光标后方 记忆方法: 在一般模式下, 光标选中字符,a表示append, 添加或者附加的意思 (3) 如果要在行首或者行…

css实现每个小盒子占32%,超出就换行

代码 <div class"visitors"><visitor class"item" v-for"(user,index) in userArr" :key"user.id" :user"user" :index"index"></visitor></div><style lang"scss" scoped&…

java乱码问题

文章目录 1.eclipse所有修改编码的地方2.io读取文件乱码问题1.读写统一2.转换字符编码&#xff1a; 3.http请求返回乱码 1.eclipse所有修改编码的地方 2.io读取文件乱码问题 1.读写统一 如果文件是以UTF-8编码保存的&#xff0c;那么在读取文件时也应使用UTF-8编码。 2.转换…

Apple Vision Pro 和其商业未来

机器人、人工智能相关领域 news/events &#xff08;专栏目录&#xff09; 本文目录 一、Vision Pro 生态系统二、Apple Vision Pro 的营销用例 随着苹果公司备受期待的进军可穿戴计算领域&#xff0c;新款 Apple Vision Pro 承载着巨大的期望。 苹果公司推出的 Vision Pro 售…

百分点科技签约潍坊市数据产业发展战略合作

近日&#xff0c;潍坊市数据产业发展战略合作签约仪式举行&#xff0c;潍坊市人民政府副市长张震生&#xff0c;潍坊市财政局党组书记、局长王金祥&#xff0c;潍坊市大数据局党组书记陈强出席大会并致辞。百分点科技受邀进行战略合作签约&#xff0c;共同见证潍坊市数据要素市…

生成式人工智能(AI)的未来

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

深度学习模型快速开发平台推荐

前言 本文面向深度学习初学者或者工程师&#xff0c;推荐几个常用的深度学习模型快速开发平台。可以帮助初学者快速跑通模型&#xff0c;帮助工程师快速对模型进行部署和应用。 huggingface 简介 不多介绍&#xff0c;全球最大的模型托管平台&#xff0c;该平台最大的特点是…

全网超详细Redis主从部署(附出现bug原因)

主从部署 整体架构图 需要再建两个CentOs7,过程重复单机部署 http://t.csdnimg.cn/zkpBE http://t.csdnimg.cn/lUU5gLinux环境下配置redis 查看自己ip地址命令 ifconfig 192.168.187.137 进入redis所在目录 cd /opt/software/redis cd redis-stable 进入配置文件 vim redi…

C++——类和对象(初始化列表和运算符重载与静态与友元)

文章目录 初始化列表语法结构定义和使用案例初始化列表初始化常量成员&#xff1a; 注意事项 运算符重载加法运算符重载语法结构示例注意事项 减法运算符重载语法结构示例注意事项 等于运算符重载等于运算符 的重载语法示例注意事项 大于运算符重载大于运算符 > 的重载语法…