c++ - ProtocolBuffer 无法定义数据,尽管它已被接收

标签 c++ protocol-buffers winsock

我正在尝试使用 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 语句有效。之后,当我尝试查看 Position 和 Health 数据时,一切都为 0。

我不知道我做错了什么。我阅读了大部分 ProtocolBuffer 教程和帮助,但似乎无济于事。

编辑: 我尝试在同一个应用程序中对数据进行序列化和反序列化(不涉及网络),并使用以下代码实现了这一点:

std::string sendData;
message->SerializeToString(&sendData);

MessageID* receivedData = new MessageID();
receivedData->ParseFromString(sendData);

如果我检查 receivedData 中的数据,它与原始对象“消息”中的数据完全相同(因此,正确的值)

最佳答案

您的问题是您正在使用 strlen() 来查找消息的长度。 strlen() 只查找第一个零值字节并假定它已经结束。这是文本字符串的约定,但不适用于 Protocol Buffer 等二进制消息。在这种情况下,strlen() 返回的大小太短,因此消息中缺少某些字段,但也可能发生相反的情况——strlen()可能会超出缓冲区的末尾并返回太长的大小,甚至会导致程序崩溃。

因此,您需要确保消息的实际确切大小从发送方传达给接收方。

关于c++ - ProtocolBuffer 无法定义数据,尽管它已被接收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24634733/

相关文章:

c++ - 创建指向返回 std::pair 的函数的成员函数指针

java - 无法通过 UDP protobuf 将大于 127 的整数值从 C++ 发送到 Java

c - 框成一个大的一维数组

c++ - 如何使用 winsock 标记客户端

c++ - 删除链表的所有其他节点

c++ - 比较迭代器和 const_iterators

c++ - 如何在不扩展命名空间 `std` 的情况下为缺少预定义运算符的标准类型定义运算符 >> (istream &, ...)?

c# - Protocol Buffer .net : how to handle inheritance without [ProtoInclude]

c++ - 在 C++ 中填充 protobuf 字段

c - TCP 接收扩展的 ASCII 或 utf-8 字符