Qt + Protobuf,类型?

17
我想在Qt开发中使用Google的协议缓冲区,但我不知道如何最好地将它们整合到项目中。
最终,我想使用protocol buffers通过QUdpSocketQTcpSocket 发送数据。
将协议缓冲区的message转换为在套接字(QByteArray)上发送的数据,再在另一端进行逆向转换的最佳方法是什么?
4个回答

15

从protobuf对象创建一个QByteArray:

Person person; // a protobuf object
person.set_id(123);
person.set_name("Bob");
person.set_email("bob@example.com");

std::ostringstream out;
person.SerializeToOstream(&out);
QByteArray byteArray(out.str().c_str());
sendSerializedPersonOverQTcpSocket(byteArray);

QByteArray 中读取 protobuf 对象:

QByteArray byteArray = readSerializedPersonFromQTcpSocket();
Person person;
if (!person.ParseFromArray(byteArray, byteArray.size())) {
  std::cerr << "Failed to parse person.pb." << std::endl;
}

4
不是完全错误,但你需要找到一种方法来识别另一端的消息。此外,你需要确定数据的长度。protobuf 内部都不会执行这两件事。另外,流输出版本是格式化程序中最慢的,向量/数组输出更快。 - edA-qa mort-ora-y
我一直在尝试使用SerializeToArray方法,但无法弄清如何将其转换为QByteArray。你能给个例子吗? - Jay
请参见下面的格式化代码 - 我不知道如何在注释中格式化代码。对此我很抱歉。\n\n void convertQByteArrayToUser(QByteArray& aByteArray) { com::your::name_space::User user; if(!user.ParseFromArray(aByteArray.data(), aByteArray.size())) { //无法解析 } else { //耶耶耶耶 if(user.has_userid()) { //... } } } - Viren
不要忘记 #include <sstream> 以使用 std::ostringstream。然而,我建议采用 @matemaciek 建议的最后一种方法。 - clickMe
@Vijay Mathew,我在哪里可以找到函数sendSerializedPersonOverQTcpSocket? - sameer karjatkar

9

改为:

std::ostringstream out;
person.SerializeToOstream(&out);
QByteArray byteArray(out.str().c_str());

你也可以这样写:

QByteArray byteArray(person.SerializeAsString().c_str());

编辑:以上两种方法得到的结果相同,但我不确定是否正确。这个方法似乎更好:

QByteArray byteArray(QString::fromStdString(person.SerializeAsString()));

编辑2:现在我知道它是如何工作的:如果序列化中有\0字符,则前两种方法都是错误的-之后的所有内容都会丢失。要纠正它,可以这样写:

QByteArray byteArray(person.SerializeAsString().c_str(), person.ByteSize());

6
使用以下代码非常危险。
std::ostringstream out;
person.SerializeToOstream(&out);
QByteArray byteArray(out.str().c_str());
sendSerializedPersonOverQTcpSocket(byteArray);

您可以在这里找到一个很好的解释:在Protobuf-C中,可选的uint32变量是否可以具有值0

从protobuf消息创建QByteArray的正确方法是:

QByteArray byteArray;
byteArray.resize(message.ByteSize());
message.SerializeToArray(byteArray.data(), byteArray.size());

3

@James:你可以使用ParseFromArray(),例如,如下所示:(请注意,ParseFromArray()仅适用于proto-buf-lite版本的库)。

void convertQByteArrayToUser(QByteArray& aByteArray)
{
    com::your::name_space::User user;
    if(!user.ParseFromArray(aByteArray.data(), aByteArray.size())) 
    {
        //could not parse
    }
    else { //yayyyyy            
        if(user.has_userid())
        {
            //...
        }
    }
}

因为错误的陈述而被踩了:仅在proto-buf-lite版本的库中可用。花了我两个小时才弄清楚它在完整版本中同样可用!引用Google Light API文档所有协议消息对象都实现了此接口。非lite消息还实现了Message接口,该接口是MessageLite的子类 - clickMe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接