我正在以数据包(64 字节)的形式向设备发送和接收二进制数据。数据具有特定的格式,其中的一部分因不同的请求/响应而异。
现在我正在为接收到的数据设计一个解释器。简单地按位置读取数据是可以的,但是当我有十几种不同的响应格式时,它看起来就不那么酷了。我目前正在考虑为此目的创建一些结构,但我不知道它如何与填充一起使用。
也许有更好的方法?
有关的:
我正在以数据包(64 字节)的形式向设备发送和接收二进制数据。数据具有特定的格式,其中的一部分因不同的请求/响应而异。
现在我正在为接收到的数据设计一个解释器。简单地按位置读取数据是可以的,但是当我有十几种不同的响应格式时,它看起来就不那么酷了。我目前正在考虑为此目的创建一些结构,但我不知道它如何与填充一起使用。
也许有更好的方法?
有关的:
您需要使用结构和或联合。您需要确保您的数据在连接的两端都正确打包,如果连接的任一端有可能以不同的方式运行,您可能希望在每一端与网络字节顺序进行相互转换字节序。
举个例子:
#pragma pack(push) /* push current alignment to stack */
#pragma pack(1) /* set alignment to 1 byte boundary */
typedef struct {
unsigned int packetID; // identifies packet in one direction
unsigned int data_length;
char receipt_flag; // indicates to ack packet or keep sending packet till acked
char data[]; // this is typically ascii string data w/ \n terminated fields but could also be binary
} tPacketBuffer ;
#pragma pack(pop) /* restore original alignment from stack */
然后在分配时:
packetBuffer.packetID = htonl(123456);
然后在收到时:
packetBuffer.packetID = ntohl(packetBuffer.packetID);
这里有一些关于字节序和对齐以及结构打包的讨论
如果你不打包结构,它最终会与字边界对齐,结构的内部布局和它的大小将不正确。
如果不知道数据的确切格式,很难说最好的解决方案是什么。您是否考虑过使用工会?
我以前做过无数次:这是一个非常常见的场景。有很多事情我几乎总是在做。
不要太担心让它成为最有效的东西。
如果我们最终花费大量时间打包和拆包数据包,那么我们总是可以改变它以提高效率。虽然我还没有遇到过我必须这样做的情况,但我还没有实施网络路由器!
虽然使用 structs/unions 是运行时最有效的方法,但它带来了许多复杂性:说服编译器打包 structs/unions 以匹配您需要的数据包的八位字节结构,努力避免对齐和字节序问题,并且缺乏安全性,因为没有或很少有机会对调试版本进行完整性检查。
我经常会得到一个包含以下类型的架构:
在所有这一切中,有可能(即使只是用于调试构建)验证每个可修改的字段都设置为一个合理的值。虽然看起来工作量很大,但很难获得格式无效的数据包,可以使用调试器轻松检查预打包数据包的内容(因为它都在正常的平台原生格式变量中)。
如果我们确实必须实现一个更高效的存储方案,那么也可以将其包装在这个抽象中,而几乎没有额外的性能成本。
我同意伍吉的观点。您也可以使用代码生成来执行此操作。使用一个简单的数据定义文件来定义所有数据包类型,然后在其上运行 python 脚本以生成原型结构和序列化/反序列化函数。
这是一个“开箱即用”的解决方案,但我建议看一下 Python构造库。
Construct 是一个用于解析和构建数据结构(二进制或文本)的 python 库。它基于以声明方式定义数据结构的概念,而不是过程代码:更复杂的结构由更简单的结构组成。它是第一个让解析变得有趣的库,而不是今天通常令人头疼的问题。
构造非常健壮和强大,只需阅读教程将帮助您更好地理解问题。作者还计划从定义中自动生成 C 代码,因此绝对值得一读。