我有一个简单的客户端/服务器,它使用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。
答案 0 :(得分:1)
set_allocated_
方法取得参数的所有权。您永远不应该传入堆栈分配的对象,只传递堆分配的对象。父消息将在稍后删除该对象。 (依赖于稍后调用release_
以防止删除是脆弱的;我建议反对它。)
对于您的节点,我建议您只使用mutable_heartbeat()
来获取子对象的实例。请注意,由于您正在重用父消息(m_Message
),内部消息也将被重用 - 当m_Message
被清除时,它会将其所有子节点放在空闲列表中以便以后重用。因此,使用mutable_heartbeat()
只会在第一次分配内存,如果这是您所担心的。
PS。而不是设置ArrayOutputStream
和CodedOutputStream
,请执行以下操作:
int size = m_Message.ByteSize();
assert(size < sizeof(buffer));
m_Message.SerializeWithCachedSizesToArray(buffer);
它会更快。
答案 1 :(得分:0)
解决方案:
退出函数前添加m_Message.release_heartbeat()。