ProtocolBuffer缺少必填字段但填写完毕

时间:2014-10-21 10:24:54

标签: c++ multithreading protocol-buffers winsock

我正在创建一个客户端 - 服务器环境,我刚刚实现了UDP。我之前只使用TCP连接进行测试,然后一切正常。 现在,如果我尝试从客户端向服务器发送数据包,我会收到一个错误,即某些必填字段未被填写,而这些字段是他们所关注的(稍后请参阅代码)。我真的不知道为什么会发生这种情况,因为它之前有效。

我认为有一点很重要,TCP套接字的接收方法和UDP套接字在不同的线程上。 (服务器使用多线程)

所以,这是一些代码:

TCP接收(部分):

iResult = recv(m_Connections[t].socket, m_TCPRecvbuf, m_TCPRecvbuflen, 0);

// Deserialize the data
MessageID* receivedData = new MessageID();
receivedData->ParseFromArray((char*)m_TCPRecvbuf, receivedData->packetsize());

我首先使用iResult在ParseFromArray中做了大小(这似乎有效)但是我改了它,所以我把大小放在数据本身。 (现在已成为receivedData-> packetsize())

UDP接收(部分)在另一个线程上:

iResult = recvfrom(m_UDPListenSocket, m_UDPRecvbuf, m_UDPRecvbuflen, 0, (struct sockaddr *)&address, &addrlen);
// Deserialize the data
MessageID* receivedData = new MessageID();
receivedData->ParseFromArray((char*)m_TCPRecvbuf, receivedData->packetsize());

这是第一次创建发送的数据包:

void NetworkInterface::SendLoginData(string username, string password)
{
// Create base message
// -----------------
MessageID message;
message.set_type(MessageID::Type::MessageID_Type_LOGINDATA);

// Create logindata
// ------------------
LoginData data = message.logindata();
data.set_username(username);
data.set_password(password);

// Create packet
// ----------------------
int size = message.ByteSize();
void* buffer = malloc(size);

message.set_packetsize(size);
message.set_clientid(0);

message.SerializeToArray(buffer, size);

if (m_pTCPNetworkingObject != nullptr)
    m_pTCPNetworkingObject->SendData(buffer, size);
else
    printf("NetworkInterface [ERROR]: No connection data was found. Please use CreateConnectionObject() first!\n");
}

之后它给出的错误是缺少Type,ClientID和packetSize字段,但是你可以看到这些字段被填入

这是SendData()方法:

void SendData(void* data, int size)
{
    // SEND DATA
    int iResult;
    iResult = send(m_TCPConnectSocket, (char*)data, size, 0 );
    if (iResult == SOCKET_ERROR) 
        printf("send failed with error: %d\n", WSAGetLastError());
}

这是我能提供的所有信息。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:0)

存在多个问题:

1)反序列化:

receivedData->ParseFromArray((char*)m_TCPRecvbuf, receivedData->packetsize());

packetSize填充之前致电parseFromArray,改为使用iResult

2)LoginData:

LoginData data = message.logindata();

这会读取空登录数据的副本,您永远不会更改message。使用

LoginData* data = message.mutable_logindata();

获取指向消息loginData的指针,并在message内修改它。

3)序列化:

int size = message.ByteSize();
void* buffer = malloc(size);

这使用空消息的大小(因为未设置loginData)。所以你永远不会发送完整的消息。 设置完所有属性后,您必须调用ByteSize()。这与您邮件中的packetSize相矛盾。 由于无论如何都不能将它用于反序列化(参见1),您应该删除此条目。