1

我需要处理由另一个非 Qt 程序创建的定义结构的流式二进制数据 (QDataStream)。我想知道解释这些数据的最佳做法是什么。假设数据在电报中是结构化的(提供了结构定义),如下所示,不能由我自己更改:

4字节头| 2字节序号| 1 字节校验和 | 10字节数据

我看到以下在“电报”类中处理数据的可能性:

  1. Telegram 类有一个私有的 QByteArray 成员变量。使用 readRawData 方法一次从流中读取所有数据(17 个字节)并将其存储在其中。变量是用公共方法访问和解释的,比如return (array.at(4)<<8) + array.at(5)序列号,不是很优雅。
  2. Telegram 类有一个与结构联合的公共 char[17] 成员变量。使用 readRawData 从流中读取所有数据并存储在其中。之后访问变量时,这仅在结构上完成,就像telegramstruct.squenceNumber我看到这种方法的潜在问题一样,如字节序和填充。
  3. Telegram 类对于每个电报字段都有私有成员变量,例如QString strHeader. 从流中读取电报时,数据直接存储在这些变量中。对于基本类型,使用 readRawData 或 operator>> 完成读取。

代码应该尽可能快,因为要处理大量数据。我在带有 MinGW 的 Windows 上使用 Qt 5.0.1。

我的问题:

  • 上述解决方案中哪一个是最佳实践和快速,还是有更好的方法?
  • 像在 1 中一样一次读取是否比在 3 中读取 4 字节、2 字节、1 字节……更快?
  • 使用 1 和 3,我不能使用提供的具有已定义结构的头文件,这是不好的做法吗?
  • 是否有可能与 QByteArray 和结构建立某种“联合”?
  • 如何使用解决方案 3 轻松计算校验和?

非常感谢您的意见和提示。

克里斯

4

1 回答 1

2

Well, sorry dont have that much time to write code examples, but will try to give a brief hints. 1) Performance issue. As soon as you have performance constrains first thing to optimise is an amounts of actual reads from the stream from where data are coming. Whatever it's File/Socket/etc it's anyway QIODevice. So first thing to do is to maintain some kind of QByteArray where you adding all data available on a QIODevice on every ready attempt/handling data received notification. So below I assume there is certain QByteArray m_rawData which holds currently unprocessed bytes, which can be some amount of Telegrams + last telegram which can be received partially.

2) I would make a class like Telegram which holds telegram data, roughly saying

class Telegram {
       QString       header;
       int           sequenceNumber;
       unsigned char checkSum;
       QByteArray    data;

       ...

       bool          checkSumOK();  // check is checksum is OK for provided data

}

with constructors and operators on your taste (you can implement copy constructor/etc).. Then I would extend this class with ( <<, >>) operators to support QDataStream which operates on temporary buffer mentioned in part 1).

So general concept is that you read data from the stream to temporary buffer as soon as possible and after read is done you fetch from resulted buffer as many Telegram's instances as possible. Then you work with QDataSteam applied on a QByteArray you can safely use read 4 bytes, read 1 byte etc calls without having that much performance impact because in general it's mostly about shifting pointers.

3) Of course if you talking about extreme condition.. you can think of unions (as being mentioned in previous answer) to make direct copy of raw data on top of a aligned structure but that way requires much more careful programming (especially taking in consideration x32/x64 archs as well as big/little endians platforms)

于 2013-04-15T16:38:01.637 回答