当前位置: 首页 > news >正文

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();}}}

相关文章:

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

设计一个可变长度的数据通信协议编码和解码代码。 要有本机ID字段&#xff0c;远端设备ID字段&#xff0c;指令类型字段&#xff0c;数据体字段&#xff0c;校验字段。其中一个要求是&#xff0c;每次固定收发八个字节&#xff0c;单个数据帧超过八个字节需要分包收发。对接收的…...

【MATLAB库函数系列】MATLAB库函数pwelch之功率谱估计的详解及实现

功率谱估计 由于实际信号通常是非定常的,我们只能假设其在10ms的时间段内是定常的,并在此基础上对短的定常信号求PSD或者能谱。 窗函数的作用就是将原始的信号分割成一段段可以计算PSD和能谱的短信号,并且保证了周期结构的连续性、避免了频谱泄漏。不同的窗函数具有不同的…...

科技出海|百分点科技智慧政务解决方案亮相非洲展会

近日&#xff0c;华为非洲全联接大会在南非约翰内斯堡举办&#xff0c;吸引政府官员行业专家、思想领袖、生态伙伴等2,000多人参会&#xff0c;百分点科技作为华为云生态合作伙伴&#xff0c;重点展示了智慧政务解决方案&#xff0c;发表《Enable a Smarter Government with Da…...

Prometheus 云原生 - Prometheus 数据模型、Metrics 指标类型、Exporter 相关

目录 开始 Prometheus 数据类型 简单理解 时序样本 格式 和 命名要求 Metrics 指标类型 Counter 计数器 Gauge Histogram Summary Exporter 相关 概述 Exporter 类型 Exporter 规范 开始 Prometheus 数据类型 简单理解 a&#xff09;安装好 Prometheus 后会暴露…...

Qt窗口程序整理汇总

到今日为止&#xff0c;通过一个个案例的实验&#xff0c;逐步熟悉了 Qt6下 窗体界面开发的&#xff0c;将走过的路&#xff0c;再次汇总整理。 Qt Splash样式的登录窗https://blog.csdn.net/castlooo/article/details/140462768 Qt实现MDI应用程序https://blog.csdn.net/cast…...

简单实现一个本地ChatGPT web服务(langchain框架)

简单实现一个本地ChatGPT 服务&#xff0c;用到langchain框架&#xff0c;fastapi,并且本地安装了ollama。 依赖安装&#xff1a; pip install langchain pip install langchain_community pip install langchain-cli # langchain v0.2 2024年5月最新版本 pip install bs4 pi…...

Elasticsearch-多边形范围查询(8.x)

目录 一、字段设计 二、数据录入 三、查询语句 四、Java代码实现 开发版本详见&#xff1a;Elasticsearch-经纬度查询(8.x-半径查询)_es经纬度范围查询-CSDN博客 一、字段设计 PUT /aoi_points {"mappings": {"properties": {"location": {…...

Kotlin Misk Web框架

Kotlin Misk Web框架 1 Misk 框架介绍2 Misk/SpringBoot 框架对比3 Misk 添加依赖/配置3.1 build.gradle.kts3.2 settings.gradle.kts3.3 gradle.properties 4 Misk 请求接口5 Misk 程序模块6 Misk 主服务类7 Misk 测试结果 1 Misk 框架介绍 Misk 是由 Square 公司开发的一个开…...

【设计模式之美】【建造型】工厂模式:通过面向接口编程思路,串起业务流程

文章目录 一. 简单工厂&#xff08;Simple Factory&#xff09;第一种简单工厂&#xff1a;面向接口编程与工厂类&#xff1a;划分功能职责第二种&#xff1a;单例简单工厂&#xff1a;节省内存和对象创建的时间 二. 工厂方法&#xff08;Factory Method&#xff09;&#xff1…...

AI算法19-偏最小二乘法回归算法Partial Least Squares Regression | PLS

偏最小二乘法回归算法简介 算法概述 偏最小二乘法模型可分为偏最小二乘回归模型和偏最小二乘路径模型。其中偏最小二乘回归模型是一种新型的多元统计方法&#xff0c;它集中了主成分分析、典型相关分析和线性回归的特点&#xff0c;特别在解决回归中的共线性问题具有无可比拟…...

live555关于RTSP协议交互流程

RTP在和h264 RTP在和h265 RTP载荷AAC live555关于RTSP协议交互流程 live555的核心数据结构值之闭环双向链表 live555 rtsp服务器实战之createNewStreamSource 概要 rtsp在交互的过程中用到很多协议:tcp,udp,rtp,rtcp,sdp等协议&#xff1b;该篇文章主要分析在live555中这些…...

Centos7 安装私有 Gitlab

在 CentOS 7上&#xff0c;下面的命令也会在系统防火墙中打开 HTTP、HTTPS 和 SSH 访问。这是一个可选步骤&#xff0c;如果您打算仅从本地网络访问极狐GitLab&#xff0c;则可以跳过它。 sudo yum install -y curl policycoreutils-python openssh-server perl sudo systemct…...

浅谈数学模型在UGC/AIGC游戏数值配置调参中的应用(AI智能体)

浅谈数学模型在UGC/AIGC游戏数值配置调参中的应用 ygluu 卢益贵 关键词&#xff1a;UGC、AIGC、AI智能体、大模型、数学模型、游戏数值调参、游戏策划 一、前言 在策划大大群提出《游戏工厂&#xff1a;AI&#xff08;AIGC/ChatGPT&#xff09;与流程式游戏开发》讨论之后就…...

第T5周:使用TensorFlow实现运动鞋品牌识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 文章目录 一、前期工作1.设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;2. 导入数据3. 查看数据 二、数据预处理1、加载数据2、数据可视化3、再…...

网络编程学习之tcp

按下*&#xff08;星号&#xff09;可以搜索当前光标下的单词。 Tcp编程的过程 打开网络设备 Bind&#xff1a;给服务地址把ip号和端口号连接进去 Tcp是有状态的 Listen是进入监听状态&#xff0c;看有没有客户端来连接服务器 Tcp比udp消耗过多资源 Upd类似于半双工&#…...

前端XMLHttpRequest、Fetch API、Axios实现文件上传、下载方法及后端Spring文件服务器处理方法

前言 本文总结Web应用开发中文件上传、下载的方法&#xff0c;即从前端表单输入文件并封装表单数据&#xff0c;然后请求后端服务器的处理过程&#xff1b;从基础的JavaScript中XmlHttpRequest对象、Fetch API实现上传、下载进行说明&#xff0c;并给出了前端常用的axios库的请…...

STM32智能交通监测系统教程

目录 引言环境准备智能交通监测系统基础代码实现&#xff1a;实现智能交通监测系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;交通监测与管理问题解决方案与优化收尾与总结 1. 引言 智能交通监测系统通…...

【利用Selenium+autoIt实现文件上传】

利用Selenium+autoIt实现文件上传 利用Selenium+autoIT实现文件上传autoIt脚本制作转换成exe文件java代码运行部分利用Selenium+autoIT实现文件上传 当你看到这篇文章时,证明你遇到了和我一样的难题。正常情况下我们利用selenium完全可以实现表单的提交和文件上传等操作。但当…...

python join

1、join函数 *.join(seq) 以*作为分隔符&#xff0c;将seq所有的元素合并为一个新的字符串 seq ABDWDPO new_seq list(.joint(seq)) # ABDWDPO #[A, B, D, W, D, P, O]...

cython加速python代码

python这个语言在使用的层面上看几乎没有缺点&#xff0c;简单易学&#xff0c;语法简单&#xff0c;唯一的弱点就是慢&#xff0c; 当然了万能的python社区是给了解决方法的&#xff0c;那就是cython 使用Cython可以显著提升Python代码的执行效率&#xff0c;特别是在涉及到数…...

React@16.x(60)Redux@4.x(9)- 实现 applyMiddleware

目录 1&#xff0c;applyMiddleware 原理2&#xff0c;实现2.1&#xff0c;applyMiddleware2.1.1&#xff0c;compose 方法2.1.2&#xff0c;applyMiddleware 2.2&#xff0c;修改 createStore 接上篇文章&#xff1a;Redux中间件介绍。 1&#xff0c;applyMiddleware 原理 R…...

level 6 day1 Linux网络编程之网络基础

v1 网络的历史和分层 TCP 是可靠传输&#xff0c;IP协议是不可靠传输 网络的体系结构 网络分层的思想&#xff1a; OSI体系结构 两层交换机是指数据链路层的交换 三层交换是指网络层这边的交换 四层模型 蓝色的字 是由手机发给PC机&#xff0c;由传输层来决定应该交给哪一…...

PostgreSQL UPDATE 命令

PostgreSQL UPDATE 命令 PostgreSQL 是一种功能强大的开源对象关系型数据库管理系统&#xff08;ORDBMS&#xff09;&#xff0c;它使用并扩展了SQL语言。在处理数据库时&#xff0c;我们经常需要更新现有的记录。在PostgreSQL中&#xff0c;UPDATE命令用于修改表中的现有记录…...

什么? CSS 将支持 if() 函数了?

CSS Working Group 简称 CSSWG, 在近期的会议中决定将 if() 添加到 CSS Values Module Level 5 中。 详情可见&#xff1a;css-meeting-bot 、[css-values] if() function 当我看到这个消息的时候&#xff0c;心中直呼这很逆天了&#xff0c;我们知道像 less 这些 css 这些预…...

function calling实现调用理杏仁api获取数据

LLM是不存在真正逻辑的且并不是知晓万事万物的&#xff08;至少目前是这样&#xff09;在很多更垂直的环境下LLM并不能很好的赋能。 function calling的实现使LLM可以对接真正的世界以及真正有逻辑的系统&#xff0c;这将很大程度上改变LLM的可用范围&#xff08;当然安全问题依…...

Excel中用VBA实现Outlook发送当前工作簿

Excel中用VBA实现Outlook发送当前工作簿&#xff0c;首先按AltF11打开VBA编辑器&#xff0c;插入模块&#xff0c;并在工具-引用中勾选 Microseft Outlook .0 Object Library(其中为你Microseft Outlook的版本号。 Sub 发送邮件() 保存当前excel ThisWorkbook.Save让excel连接…...

从 ArcMap 迁移到 ArcGIS Pro

许多 ArcMap 用户正在因 ArcGIS Pro 所具有的现代 GIS 桌面工作流优势而向其迁移。 ArcGIS Pro 与其余 ArcGIS 平台紧密集成&#xff0c;使您可以更有效地共享和使用内容。 它还将 2D 和 3D 组合到一个应用程序中&#xff0c;使您可以在同一工程中使用多个地图和多个布局。 Arc…...

WSL2 的安装与运行 Linux 系统

前言 适用于 Linux 的 Windows 子系统 (WSL) 是 Windows 的一项功能&#xff0c;允许开发人员在 Windows 系统上直接安装并使用 Linux 发行版。不用进行任何修改&#xff0c;也无需承担传统虚拟机或双启动设置的开销。 可以将 WSL 看作也是一个虚拟机&#xff0c;但是它更为便…...

业务终端动态分配IP-DHCP技术、DHCP中继技术

一、为什么需要DHCP? 1、许多设备(主机、无线WiFi终端等)需要动态地址的分配; 2、人工手工配置任务繁琐、容易出错,比如:IP地址冲突; 3、网络规模扩大、复杂度提高,网络配置越来越复杂,计算机的位置变化和数量超过可分配IP地址的数量,造成IP地址变法频繁以及IP地址…...

新一代大语言模型 GPT-5 对工作与生活的影响及应对策略

文章目录 &#x1f4d2;一、引言 &#x1f4d2;二、GPT-5 的发展背景 &#x1f680;&#xff08;一&#xff09;GPT-4 的表现与特点 &#x1f680;&#xff08;二&#xff09;GPT-5 的预期进步 &#x1f4d2;三、GPT-5 对工作的影响 &#x1f680;&#xff08;一&#xf…...