C# 优雅高效的读取字节数组

169 阅读2分钟

前言

在开发上位机的经历中,会有很多需要和下位机交互通信的场景,大多数都会定义一个和硬件的通信协议,最终在上位机代码中的形式其实就是符合通信协议的字节数组。

场景

在控制一些车辆进行货物搬运的业务场景下,我们需要即时的获取小车的状态数据,并且做出解析,最后进行业务处理。不管与下位机是如何通信的,最终都会读取到一个字节数组在内存中。

以TCP通讯为例子,一般会在通讯协议的报文头中定义报文的长度,从而解决一些通讯问题,如粘包等,最后读取到正文部分。

如何解析字节数组到类或结构体中

建立与通信协议一致的结构体

比如通讯协议的正文格式定义如下:

idmotor_stepsspeed
1字节2字节1字节

1、id 小车编号

2、motor_steps 小车行走累计马达步数

3、speed 小车当前速度

在代码中建立对应的结构体

[StructLayout(LayoutKind.Explicit)]
public struct VehicleStatus
{
    [FieldOffset(0)] public byte id;
    [FieldOffset(1)] public ushort motor_steps;
    [FieldOffset(3)] public byte speed;
}

使用不安全代码将字节数组映射到结构体中

byte[] metaData = new byte[4] { 10, 88, 89, 5 }; //模拟一段报文
unsafe
{
    fixed (byte* metaPointer = metaData)
    {
        VehicleStatus* status = (VehicleStatus*)metaPointer;

        Console.WriteLine($"小车编号:{status->id}");
        Console.WriteLine($"小车速度:{status->speed}");
        Console.WriteLine($"小车马达步数:{status->motor_steps}");
    }
}

代码解释

StructLayout

表示某个类或者结构体里的成员的排列方式,这里我们使用LayoutKind.Explicit精确模式,该模式必须配合FieldOffset属性一起制定字段的物理内存排列位置。

fixed

用来钉住可移动变量,确保GC在执行期间对不会重新定位或释放包含对象实例,如果位置变了或者被释放了,谁还管你的非托管的指针对象呢?这边字节数组肯定是一个可移动变量了。

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:BruceNeter

出处:cnblogs.com/qwqwQAQ/p/17428679.html

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!