C++ 使用Qt跨HTTP的协议缓冲区序列化中的空白

C++ 使用Qt跨HTTP的协议缓冲区序列化中的空白,c++,qt,http,serialization,protocol-buffers,C++,Qt,Http,Serialization,Protocol Buffers,我正试图通过HTTP连接发送一个Google协议缓冲区序列化字符串,并将其接收回(未修改),在那里我将对其进行反序列化。我的问题似乎是'serializeToString'方法,它接受我的字符串,并似乎向序列化字符串添加换行符(可能还有其他空格)。在下面的例子中,我使用字符串“camera_stuff”,在序列化它之后,我得到一个前面有新行的QString。我尝试过其他字符串,结果相同,只是添加了不同的空格和换行符。这会导致反序列化操作出现问题,因为HTTP请求中未捕获空格,因此无法成功解码包含

我正试图通过HTTP连接发送一个Google协议缓冲区序列化字符串,并将其接收回(未修改),在那里我将对其进行反序列化。我的问题似乎是'serializeToString'方法,它接受我的字符串,并似乎向序列化字符串添加换行符(可能还有其他空格)。在下面的例子中,我使用字符串“camera_stuff”,在序列化它之后,我得到一个前面有新行的QString。我尝试过其他字符串,结果相同,只是添加了不同的空格和换行符。这会导致反序列化操作出现问题,因为HTTP请求中未捕获空格,因此无法成功解码包含来自服务器的序列化字符串的响应。如果我猜到序列化字符串中的空白,我可以部分解码它。我怎样才能解决这个问题?请参阅以下代码-谢谢

我有一个协议缓冲区.proto文件,看起来像:

message myInfo {
  required string data = 1;
  required int32 number = 2;
}
运行protoc编译器后,我在其中构建了如下Qt:

// Now Construct our Protocol Buffer Data to Send
myInfo testData;
testData.set_data("camera_stuff");
testData.set_number(123456789);
// Serialize the protocol buffer to a string
std::string serializedProtocolData; // Create a standard string to serialize the protocol buffer contents to
myInfo.SerializeToString(&serializedProtocolData); // Serialize the contents to the string
QString serializedProtocolDataAsQString = QString::fromStdString(serializedProtocolData);
// Print what we are sending
qDebug() << "Sending Serialized String: " << serializedProtocolDataAsQString;
qDebug() << "Sending Serialized String (ASCII): " << serializedProtocolDataAsQString.toAscii();
qDebug() << "Sending Serialized String (UTF8): " << serializedProtocolDataAsQString.toUtf8();
qDebug() << "Sending Serialized Protocol Buffer";
qDebug() << "Data Number: " << QString::fromStdString(myInfo.data());
qDebug() << "Number: " << (int)myInfo.number();
// Now deserialize the protocol buffer
string = "\n\n" + string; // Notice that if I don't add the newlines I get nothing!
myInfo protocolBuffer;
protocolBuffer.ParseFromString(string.toStdString().c_str());
std::cout << "DATA: " << protocolBuffer.model() << std::endl;
std::cout << "NUMBER: " << protocolBuffer.serial() << std::endl;
qDebug() << "Received Serialized String: " << string;
qDebug() << "Received Deserialized Protocol Buffer";
qDebug() << "Data: " << QString::fromStdString(protocolBuffer.data());
qDebug() << "Number: " << (int)protocolBuffer.number();
我将数据序列化为如下字符串:

// Now Construct our Protocol Buffer Data to Send
myInfo testData;
testData.set_data("camera_stuff");
testData.set_number(123456789);
// Serialize the protocol buffer to a string
std::string serializedProtocolData; // Create a standard string to serialize the protocol buffer contents to
myInfo.SerializeToString(&serializedProtocolData); // Serialize the contents to the string
QString serializedProtocolDataAsQString = QString::fromStdString(serializedProtocolData);
// Print what we are sending
qDebug() << "Sending Serialized String: " << serializedProtocolDataAsQString;
qDebug() << "Sending Serialized String (ASCII): " << serializedProtocolDataAsQString.toAscii();
qDebug() << "Sending Serialized String (UTF8): " << serializedProtocolDataAsQString.toUtf8();
qDebug() << "Sending Serialized Protocol Buffer";
qDebug() << "Data Number: " << QString::fromStdString(myInfo.data());
qDebug() << "Number: " << (int)myInfo.number();
// Now deserialize the protocol buffer
string = "\n\n" + string; // Notice that if I don't add the newlines I get nothing!
myInfo protocolBuffer;
protocolBuffer.ParseFromString(string.toStdString().c_str());
std::cout << "DATA: " << protocolBuffer.model() << std::endl;
std::cout << "NUMBER: " << protocolBuffer.serial() << std::endl;
qDebug() << "Received Serialized String: " << string;
qDebug() << "Received Deserialized Protocol Buffer";
qDebug() << "Data: " << QString::fromStdString(protocolBuffer.data());
qDebug() << "Number: " << (int)protocolBuffer.number();
然后我像这样打印出来:

// Now Construct our Protocol Buffer Data to Send
myInfo testData;
testData.set_data("camera_stuff");
testData.set_number(123456789);
// Serialize the protocol buffer to a string
std::string serializedProtocolData; // Create a standard string to serialize the protocol buffer contents to
myInfo.SerializeToString(&serializedProtocolData); // Serialize the contents to the string
QString serializedProtocolDataAsQString = QString::fromStdString(serializedProtocolData);
// Print what we are sending
qDebug() << "Sending Serialized String: " << serializedProtocolDataAsQString;
qDebug() << "Sending Serialized String (ASCII): " << serializedProtocolDataAsQString.toAscii();
qDebug() << "Sending Serialized String (UTF8): " << serializedProtocolDataAsQString.toUtf8();
qDebug() << "Sending Serialized Protocol Buffer";
qDebug() << "Data Number: " << QString::fromStdString(myInfo.data());
qDebug() << "Number: " << (int)myInfo.number();
// Now deserialize the protocol buffer
string = "\n\n" + string; // Notice that if I don't add the newlines I get nothing!
myInfo protocolBuffer;
protocolBuffer.ParseFromString(string.toStdString().c_str());
std::cout << "DATA: " << protocolBuffer.model() << std::endl;
std::cout << "NUMBER: " << protocolBuffer.serial() << std::endl;
qDebug() << "Received Serialized String: " << string;
qDebug() << "Received Deserialized Protocol Buffer";
qDebug() << "Data: " << QString::fromStdString(protocolBuffer.data());
qDebug() << "Number: " << (int)protocolBuffer.number();
客户端按如下方式反序列化消息:

// Now Construct our Protocol Buffer Data to Send
myInfo testData;
testData.set_data("camera_stuff");
testData.set_number(123456789);
// Serialize the protocol buffer to a string
std::string serializedProtocolData; // Create a standard string to serialize the protocol buffer contents to
myInfo.SerializeToString(&serializedProtocolData); // Serialize the contents to the string
QString serializedProtocolDataAsQString = QString::fromStdString(serializedProtocolData);
// Print what we are sending
qDebug() << "Sending Serialized String: " << serializedProtocolDataAsQString;
qDebug() << "Sending Serialized String (ASCII): " << serializedProtocolDataAsQString.toAscii();
qDebug() << "Sending Serialized String (UTF8): " << serializedProtocolDataAsQString.toUtf8();
qDebug() << "Sending Serialized Protocol Buffer";
qDebug() << "Data Number: " << QString::fromStdString(myInfo.data());
qDebug() << "Number: " << (int)myInfo.number();
// Now deserialize the protocol buffer
string = "\n\n" + string; // Notice that if I don't add the newlines I get nothing!
myInfo protocolBuffer;
protocolBuffer.ParseFromString(string.toStdString().c_str());
std::cout << "DATA: " << protocolBuffer.model() << std::endl;
std::cout << "NUMBER: " << protocolBuffer.serial() << std::endl;
qDebug() << "Received Serialized String: " << string;
qDebug() << "Received Deserialized Protocol Buffer";
qDebug() << "Data: " << QString::fromStdString(protocolBuffer.data());
qDebug() << "Number: " << (int)protocolBuffer.number();

你看,问题是我猜不到空格,所以我似乎无法可靠地反序列化我的字符串。有什么想法吗?

序列化的protobuf不能被视为
C
字符串,因为它可能已经嵌入了NUL。它是一种二进制协议,使用所有可能的八位字节值,只能通过8位干净连接发送。它也是无效的UTF-8序列,不能作为Unicode进行序列化和反序列化。因此,
QString
也不是存储序列化protobuf的有效方法,我怀疑这可能也会给您带来问题

您可以使用
std::string
QByteArray
。我强烈建议你避免做其他事情。特别是,这是错误的:

protocolBuffer.ParseFromString(string.toStdString().c_str());
因为它将在第一次
NUL
时截断protobuf。(您的测试消息没有任何内容,但这迟早会影响您。)


至于通过HTTP发送消息,您需要能够确保消息中的所有字节都按原样发送,这也意味着您需要显式发送长度。您没有包含实际发送和接收消息的代码,因此我无法对其进行评论(而且我对Qt HTTP库的了解还不够透彻),但从消息前面删除
0x0A
的事实表明您遗漏了一些内容。确保在消息部分正确设置了内容类型(例如,不是文本)

谢谢你的回答。这解决了我的问题,非常清楚。