5

我正在以数据包(64 字节)的形式向设备发送和接收二进制数据。数据具有特定的格式,其中的一部分因不同的请求/响应而异。

现在我正在为接收到的数据设计一个解释器。简单地按位置读取数据是可以的,但是当我有十几种不同的响应格式时,它看起来就不那么酷了。我目前正在考虑为此目的创建一些结构,但我不知道它如何与填充一起使用。

也许有更好的方法?


有关的:

4

5 回答 5

8

您需要使用结构和或联合。您需要确保您的数据在连接的两端都正确打包,如果连接的任一端有可能以不同的方式运行,您可能希望在每一端与网络字节顺序进行相互转换字节序。

举个例子:

#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);

这里有一些关于字节序对齐以及结构打包的讨论

如果你不打包结构,它最终会与字边界对齐,结构的内部布局和它的大小将不正确。

于 2009-05-12T12:04:23.143 回答
3

如果不知道数据的确切格式,很难说最好的解决方案是什么。您是否考虑过使用工会?

于 2009-05-12T12:03:44.470 回答
3

我以前做过无数次:这是一个非常常见的场景。有很多事情我几乎总是在做。

不要太担心让它成为最有效的东西。

如果我们最终花费大量时间打包和拆包数据包,那么我们总是可以改变它以提高效率。虽然我还没有遇到过我必须这样做的情况,但我还没有实施网络路由器!

虽然使用 structs/unions 是运行时最有效的方法,但它带来了许多复杂性:说服编译器打包 structs/unions 以匹配您需要的数据包的八位字节结构,努力避免对齐和字节序问题,并且缺乏安全性,因为没有或很少有机会对调试版本进行完整性检查。

我经常会得到一个包含以下类型的架构:

  • 数据包基类。任何公共数据字段都可以访问(但不可修改)。如果数据不是以打包格式存储的,那么就会有一个虚函数来生成打包数据包。
  • 从通用数据包类型派生的特定数据包类型的许多表示类。如果我们使用打包函数,那么每个表示类都必须实现它。
  • 可以从表示类的特定类型(即来自公共数据字段的数据包类型 id)推断出的任何内容都作为初始化的一部分处理,否则不可修改。
  • 每个表示类都可以从一个未打包的数据包构建,或者如果数据包数据对该类型无效,则将正常失败。然后为了方便起见,可以将其包装在工厂中。
  • 如果我们没有可用的 RTTI,我们可以使用数据包 id 来获取“穷人的 RTTI”,以确定对象真正是哪个特定的表示类。

在所有这一切中,有可能(即使只是用于调试构建)验证每个可修改的字段都设置为一个合理的值。虽然看起来工作量很大,但很难获得格式无效的数据包,可以使用调试器轻松检查预打包数据包的内容(因为它都在正常的平台原生格式变量中)。

如果我们确实必须实现一个更高效的存储方案,那么也可以将其包装在这个抽象中,而几乎没有额外的性能成本。

于 2009-05-12T20:22:20.033 回答
1

我同意伍吉的观点。您也可以使用代码生成来执行此操作。使用一个简单的数据定义文件来定义所有数据包类型,然后在其上运行 python 脚本以生成原型结构和序列化/反序列化函数。

于 2009-05-12T23:30:52.987 回答
1

这是一个“开箱即用”的解决方案,但我建议看一下 Python构造库。

Construct 是一个用于解析和构建数据结构(二进制或文本)的 python 库。它基于以声明方式定义数据结构的概念,而不是过程代码:更复杂的结构由更简单的结构组成。它是第一个让解析变得有趣的库,而不是今天通常令人头疼的问题。

构造非常健壮和强大,只需阅读教程将帮助您更好地理解问题。作者还计划从定义中自动生成 C 代码,因此绝对值得一读。

于 2009-05-15T12:30:59.757 回答