Protobuf联盟消息例外

时间:2014-05-08 13:56:18

标签: c++ protocol-buffers

我有一个简单的客户端/服务器,它使用Protobuf来回发送消息。我正在尝试使用一个带有消息的联盟,其中包含可能的消息类型的联合。请参阅下面的原型文件。

import "Heartbeat.proto";

message PBMessage
{
    optional Heartbeat heartbeat = 1;
    optional HeartbeatAck heartbeatAck = 2;
}

heartbeat.proto包含其他消息的定义。

我尝试在邮件中添加心跳并将其发送到服务器。服务器实际收到此消息,但似乎客户端在函数返回时执行清理,然后排除。我相信这与set_allocated_heartbeat函数调用有关。我试图让心跳结构本身成为班级的一员但却什么都没改变。

以下是发送有听力消息的客户端代码。

void MyClass::sendHeartBeat(void)
{
    HsmHeartbeat heartbeat;
    unsigned char buffer[1024];

    heartbeat.set_sequenceid(m_currentHBSequence++);

    m_Message.set_allocated_heartbeat(&heartbeat);

    if(heartbeat.IsInitialized() && m_Message.IsInitialized())
    {        
        google::protobuf::io::ArrayOutputStream arr(buffer, sizeof(buffer));
        google::protobuf::io::CodedOutputStream output(&arr);

        m_Message.SerializeToCodedStream(&output);

        sendto(m_ClientSocket, (char*) buffer, output.ByteCount(), 0, (sockaddr *) &m_ClientSendSocket, sizeof(m_ClientSendSocket));
    }
}

这是堆栈跟踪:

*** glibc detected *** ./client: free(): invalid pointer: 0xbfd882e0 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x73e42)[0xb74d2e42]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xb76f851f]
./client[0x804a7a2]
./client[0x804da00]
./client[0x804d7a3]
./client[0x804db01]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb74784d3]
./client[0x804a179]

编辑:澄清,m_Message是PBMessage。

2 个答案:

答案 0 :(得分:1)

set_allocated_方法取得参数的所有权。您永远不应该传入堆栈分配的对象,只传递堆分配的对象。父消息将在稍后删除该对象。 (依赖于稍后调用release_以防止删除是脆弱的;我建议反对它。)

对于您的节点,我建议您只使用mutable_heartbeat()来获取子对象的实例。请注意,由于您正在重用父消息(m_Message),内部消息也将被重用 - 当m_Message被清除时,它会将其所有子节点放在空闲列表中以便以后重用。因此,使用mutable_heartbeat()只会在第一次分配内存,如果这是您所担心的。

PS。而不是设置ArrayOutputStreamCodedOutputStream,请执行以下操作:

int size = m_Message.ByteSize();
assert(size < sizeof(buffer));
m_Message.SerializeWithCachedSizesToArray(buffer);

它会更快。

答案 1 :(得分:0)

解决方案:

退出函数前添加m_Message.release_heartbeat()。