我正在尝试使用Google的ProtocolBuffer在服务器/客户端架构中发送/接收数据。我可以用winsock连接这两个,我可以用它从ProtocolBuffer发送和接收数据,但是在服务器上反序列化数据似乎有问题(我没有做相反的事情,所以我无法分辨如果可行的话)
以下是我用来创建要发送到服务器的示例数据包的代码:
MessageID *message = new MessageID();
message->set_type(MessageID::Type::MessageID_Type_PLAYERDATA);
PlayerData::Vector2 *position = new PlayerData::Vector2();
position->set_x(10.0f);
position->set_y(25.0f);
PlayerData *data = new PlayerData();
data->set_health((UINT32)50);
data->set_allocated_position(position);
auto inventory = data->add_items();
inventory->set_itemid((INT32)1);
inventory->set_count((INT32)5);
message->set_allocated_playerdata(data);
m_pNetworkObject->Send(message);
这是实际通过TCP连接发送数据的代码:
// Serialize to string.
std::string sendData;
data->SerializeToString(&sendData);
// Convert data to const char*
const char* dataToSend = sendData.c_str();
int iResult;
iResult = send( ConnectSocket, dataToSend, data->ByteSize(), 0 );
if (iResult == SOCKET_ERROR)
{
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
exit(1);
}
所以,这是在客户端上运行的代码。现在,当我在服务器上收到此消息时,我从ProtocolBuffer中收到以下错误:
Can't parse message of type "MessageID" because it is missing required fields: type
Can't parse message of type "PlayerData" because it is missing required fields: Position, Health
服务器上反编译winsock数据的代码如下:
// decompile to a proto file and check ID
MessageID* receivedData = new MessageID();
receivedData->ParseFromArray(&recv, strlen(recv));
// check and redeserialize
switch (receivedData->type())
{
case MessageID::Type::MessageID_Type_PLAYERDATA:
{
PlayerData* playerData = new PlayerData();
playerData->ParseFromArray(&recv, strlen(recv));
UsePlayerData(sock, playerData);
break;
}
case MessageID::Type::MessageID_Type_WORLDDATA:
{
WorldData* worldData = new WorldData();
worldData->ParseFromArray(&recv, strlen(recv));
UseWorldData(sock, worldData);
break;
}
}
奇怪的是,尽管错误表明数据不包含Type值,但它确实将其设置为1并且switch语句有效。之后,当我尝试查看位置和健康数据时,一切都是0。
我不知道我做错了什么。我阅读了大部分的ProtocolBuffer教程和帮助,但似乎无济于事。
编辑: 我尝试序列化然后反序列化同一个应用程序中的数据(没有涉及网络),并使用以下代码完成它:
std::string sendData;
message->SerializeToString(&sendData);
MessageID* receivedData = new MessageID();
receivedData->ParseFromString(sendData);
如果我检查receivedData中的数据,它与原始对象“message”中的数据完全相同(正确的值)
答案 0 :(得分:1)
您的问题是您使用strlen()
来查找邮件的长度。 strlen()
只查找第一个零值字节,并假设结束。这是文本字符串的约定,但不适用于协议缓冲区之类的二进制消息。在这种情况下,strlen()
返回的大小太短,因此消息中缺少某些字段,但反之亦然 - strlen()
可以在缓冲区的末尾运行并返回大小太长,甚至崩溃你的程序。
因此,您需要确保将邮件的实际确切大小从发件人传达给接收者。