【问题标题】:Send a Struct via UDP通过 UDP 发送结构体
【发布时间】:2016-05-26 12:03:03
【问题描述】:

我想通过 QUdpSocket 发送一个结构。 我知道我应该使用QDataStream 和QByteArray,但我不能,因为接收者不会使用Qt。

我尝试了很多东西,但我从来没有找到似乎正确工作的东西。

我的结构是:

typedef struct myStruct
    {
       int nb_trame;
       std::vector<bool>  vBool;
       std::vector<int>   vInt;
       std::vector<float> vFloat;
    } myStruct;

我该如何正确地做到这一点?

【问题讨论】:

  • 你需要在发送前serialize结构内容,然后在接收端反序列化。看看这个other question 例如。
  • @SanderDeDycker 这是问题所在,我以前从未这样做过,也找不到任何可以解释的东西。我不想复制/粘贴我不理解的东西....
  • 我提供了两个链接,可以作为您了解序列化的起点。如果您需要更多阅读材料,只需使用关键字“序列化”进行搜索,就会找到很多。
  • 不要。不要使用structs 作为网络协议。使用网络协议作为网络协议。首先以八位字节在纸上定义协议,然后为自己编写一个库来发送和接收它。这样你就引入了六个外部依赖项,这些依赖项会回来并咬你。

标签: c++ networking struct qudpsocket


【解决方案1】:

对此的解决方案称为serialization

序列化是将数据结构或对象状态转换为可以存储(例如,在文件或内存缓冲区中,或通过网络连接链路传输)并稍后在相同或另一个计算机环境中重建的格式的过程.

以下是如何使用 QDataStream 序列化上述结构的完整示例:

// main.cpp
#include <limits>
#include <QDataStream>
#include <QVector>
#include <vector>

typedef struct myStruct
{
   int nb_trame;
   std::vector<bool>  vBool;
   std::vector<int>   vInt;
   std::vector<float> vFloat;

   void serialize(QDataStream &out) {
       out << nb_trame;
       out << QVector<bool>::fromStdVector(vBool);
       out << QVector<qint32>::fromStdVector(vInt);
       out << QVector<float>::fromStdVector(vFloat);
   }
} myStruct;

void fillData(myStruct &s) {
    s.nb_trame = 0x42;

    s.vBool.push_back(true);
    s.vBool.push_back(false);
    s.vBool.push_back(false);
    s.vBool.push_back(true);

    s.vInt.push_back(0xB0);
    s.vInt.push_back(0xB1);
    s.vInt.push_back(0xB2);
    s.vInt.push_back(0xB3);

    s.vFloat.push_back(std::numeric_limits<float>::min());
    s.vFloat.push_back(0.0);
    s.vFloat.push_back(std::numeric_limits<float>::max());
}

int main()
{
    myStruct s;

    fillData(s);

    QByteArray buf;
    QDataStream out(&buf, QIODevice::WriteOnly);
    s.serialize(out);
}

然后你可以用QUdpSocket::writeDatagram()发送buf


QDataStream 如何序列化

如果我们替换

QByteArray buf;
QDataStream out(&buf, QIODevice::WriteOnly);

与

QFile file("file.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);

序列化的数据被写入文件“file.dat”。这是上面代码生成的数据:

> hexdump -C file.dat
00000000  00 00 00 42 00 00 00 04  01 00 00 01 00 00 00 04  |...B............|
00000010  00 00 00 b0 00 00 00 b1  00 00 00 b2 00 00 00 b3  |................|
00000020  00 00 00 03 38 10 00 00  00 00 00 00 00 00 00 00  |....8...........|
00000030  00 00 00 00 47 ef ff ff  e0 00 00 00              |....G.......|
  • 数据以四个字节开头,代表成员 nb_trame (00 00 00 42)
  • 接下来的八个字节是向量 vBool (00 00 00 04 01 00 00 01) 的序列化形式
    • 00 00 00 04 --> 向量中的条目数
    • 01 00 00 01 --> 对,错,错,对
  • 接下来的 20 个字节用于 vInt (00 00 00 04 00 00 00 b0 00 00 00 b1 00 00 00 b2 00 00 00 b3)
    • 00 00 00 04 --> 向量中的条目数
    • 00 00 00 b0 00 00 00 b1 00 00 00 b2 00 00 00 b3 --> 0xB0、0xB1、0xB2、0xB3(每个条目 4 个字节)
  • 接下来的 28 个字节用于 vFloat (00 00 00 03 38 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 47 ef ff ff e0 00 00 00)
    • 00 00 00 03 --> 向量中的条目数
    • 38 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 47 ef ff ff e0 00 00 00 --> 1.1754943508222875e-38, 0.0, 3.4028234663852886e+38(每个条目 8 个字节)

附加信息(原始发布)

序列化不是一个微不足道的话题,但是有很多库可以帮助您解决这个问题。最后,您有两种选择:

  1. 定义您自己的序列化格式
  2. 使用现有的序列化格式
    1. 二进制
    2. 基于文本(例如 JSON、XML)

您选择哪一种在很大程度上取决于您的需求和用例。一般来说,我更喜欢已建立的格式而不是自酿。基于文本的格式本质上不太紧凑,需要更多空间,因此也需要带宽。这是您在决定格式时应该考虑的因素。另一方面,基于文本/人类可读的格式具有更容易调试的优点,因为您可以在文本编辑器中打开它们。您还应该考虑更多因素。

序列化之所以有效,是因为您不依赖于机器相关的东西。您唯一需要注意的是序列化数据是一致的并遵循定义的格式。所以对于序列化的数据,你确切地知道字节顺序是如何定义的,具体数据存储在哪里等等。

这个想法是发送方序列化数据,通过任何需要的通道发送,然后接收方再次反序列化数据。数据以哪种格式存储在两边都无关紧要。

   +--------------------------------+             +--------------------------------+
   | Host A                         |             | Host B                         |
   |                                |             |                                |
   |                                |             |                                |
   |                                |             |                                |
   |  +-------------------------+   |             |  +-------------------------+   |
   |  |         Raw data        |   |             |  |         Raw data        |   |
   |  |(Specific to plattfrom A)|   |             |  |(Specific to plattfrom B)|   |
   |  +-------------------------+   |             |  +-------------------------+   |
   |               |                |             |               ^                |
   |               | serialize      |             |               | deserialize    |
   |               v                |             |               |                |
   |      +-----------------+       |  transmit   |      +-----------------+       |
   |      | Serialized Data +----------------------------> Serialized Data |       |
   |      +-----------------+       |             |      +-----------------+       |
   |                                |             |                                |
   +--------------------------------+             +--------------------------------+

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-18
    • 1970-01-01
    • 2015-01-21
    相关资源
    最近更新 更多