これに対する解決策はシリアライゼーションと呼ばれます
シリアライゼーションとは、データ構造またはオブジェクトの状態を、(たとえば、ファイルまたはメモリ バッファーに格納したり、ネットワーク接続リンクを介して送信したりして) 格納できる形式に変換し、後で同じまたは別のコンピューター環境で再構築するプロセスです。
以下は、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);
}
buf
次に、で送信できますQUdpSocket::writeDatagram()
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
)を表す 4 バイトで始まります。
- 次の 8 バイトは、ベクトル 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 バイト)
追加情報 (元の投稿)
シリアライゼーションは些細なトピックではありませんが、それを支援する多くのライブラリがあります。最終的に、次の 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 | |
| +-----------------+ | | +-----------------+ |
| | | |
+--------------------------------+ +--------------------------------+