我正在创建一个客户端服务器应用程序,现在我正在处理一种最简单的方法,将一些类序列化,交付给另一方,然后放回到我可以使用的类中。
我意识到这并不简单,有些人可能会说在C或C ++这样的低级语言中是不可能的,但它实际上可以用很多编码来实现。我想知道是否其他人已经没有为此创建一个解决方案,这个解决方案是便携式的并且可以工作以便我不需要重新发明轮子。
目前我的解决方案(可能有点过于复杂):
每个要序列化和反序列化的类都是从包含2个函数的抽象类Serializable
继承而来的:
QHash<QString, QVariant> ToHash();
void LoadHash(QHash<QString, QVariant> hash);
第一个函数创建一个包含所有公共和私有变量的QHash。第二个函数加载此哈希并填充它们所属的值。因此,我可以将我需要序列化的所有结构转换为QHash
,并根据需要将其返回。
现在棘手的部分是通过网络将此交付给另一方。我决定为此创建一个超级简单的TCP协议。
我可以使用QDataStream
将此QHash
转换为字节数组,并且(文档说,虽然我担心可能会有一些隐藏的警告)回到QHash
使用同一个班级。
这意味着,我有办法将结构序列化为QByteArray
并且我可以将它们转换回来,现在我需要发送和接收它们。
因为我正在传输二进制数据,所以我决定不对这些&#34;数据块&#34;使用某种分隔符。因为我不想搞砸这些分隔符的复杂转义,而是我决定创建一个固定大小的标题(我将字节大小存储在常量中称为HEADER_SIZE
,目前它是8个字节)。客户端和服务器上的标头大小必须相同。
我要做的是我获取生成的QByteArray
(序列化类),获取它的大小并从中创建标题,其长度恰好是HEADER_SIZE
个字节,放入一个实际大小的序列化在那里的结构并将其添加到QByteArray
。然后我把这个数组发送到另一边。
另一方面,我正在等待第一个HEADER_SIZE
字节,然后获得与标头中描述的字节数完全相同的字节数,从而形成QHash
。 (我还没有这个代码,它现在只是一个理论算法)。
这是一种正确的方法吗?难道还有更简单的方法吗?还是已经为我处理过这个问题的东西?我应该注意一些警告吗?
为了让它更清楚一点,这是我想要做的伪图:
答案 0 :(得分:3)
您可以而且应该利用QDataStream
。而不是从Serializable
派生,只需为要序列化的每个QDataStream & operator<<(QDataStream &, Type & const)
实施QDataStream & operator>>(QDataStream &, Type &)
和Type
。
然后,您只需通过QByteArray
将所有数据转储到QDataStream
。您传输数组的大小,然后是其内容。在接收端,您将收到大小,然后是内容,在其上设置数据流,并将数据拉出。它应该是无缝的。
只要正确实施各个流媒体运营商,就会自动处理数据块分离。选择QHash
作为序列化的手段是不必要的限制 - 它可能是某些类的好选择,但对其他类则不是。
您应该序列化为QHash
,而不是序列化为QDataStream
。但是,操作员可以是独立的功能,因此您不需要从任何特殊的接口类派生。编译器会提醒您任何缺少的运算符。
This is a very simple example,通过UDP工作。
This is a larger example显示了面向未来的版本控制的详细信息,并显示了相当复杂的数据结构的序列化 - QAbstractItemModel
。
一般来说,三个对象a,b,c
的序列化可能如下所示:
static const QDataStream::Version kDSVersion = QDataStream::Qt_5_5;
void Foo::send() {
QByteArray buf;
QDataStream bds(&buf, QIODevice::WriteOnly));
bds.setVersion(kDSVersion);
bds << a << b << c;
QDataStream ds(socket, QIODevice::WriteOnly);
ds.setVersion(kDSVersion);
ds << buf; // buffer size followed by data
}
在接收端:
void Foo::readyReadSlot() {
typedef quint32 QBALength;
if (socket->bytesAvailable() < sizeof(QBALength)) return;
auto buf = socket->peek(sizeof(QBALength));
QDataStream sds(&buf);
// We use a documented implementation detail:
// See http://doc.qt.io/qt-5/datastreamformat.html
// A QByteArray is serialized as a quint32 size followed by raw data.
QBALength size;
sds >> size;
if (size == 0xFFFFFFFF) {
// null QByteArray, discard
socket.read(sizeof(QBALength));
return;
}
if (socket->bytesAvailable() < size) return;
QByteArray buf;
QDataStream bds(&socket);
bds.setVersion(kDSVersion);
bds >> buf;
QDataStream ds(&buf);
ds.setVersion(kDSVersion);
ds >> a >> b >> c;
}
答案 1 :(得分:0)
是的,有人已经发明了这个。
建议您查看谷歌协议缓冲区。它不仅可以在c ++实现和处理器体系结构之间移植,而且还可以在不同语言之间移植。
答案 2 :(得分:0)
您可以使用JSON协议
发送这样的结构:
{"employees":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}]}
你可以根据需要制作它。
Qt有QJsonObject库,可以很容易地使用它。