如果设置 protobuf 可序列化 class 的值,为什么会出现 zmq 错误?
Why was there a zmq error, if setting a value of a protobuf serializable class?
我正在测试使用 zmq 作为套接字和网络工具以及使用 protobuf 进行序列化的代码。
代码接收一个 zmq_message 并将其解析为 protobuf class,在 return 我更改其中一个 class 成员的值并发送相同的值class 返回请求者。
在此过程中,zmq 断言 check()
以某种方式失败。我真的不知道为什么会这样,因为我觉得一切都很好。
主文件中的代码如下所示:
zmq::socket_t external(context, ZMQ_REP);
external.bind("tcp://*:29067");
zmq::message_t request;
external.recv(&request);
msg.deserialize(request);
msg.set_probed_value(12.0);
zmq::message_t response = msg.serialize();
external.send(response);
反序列化方法如下所示。
_msg.ParseFromString(reinterpret_cast<const char*>(msg.data()));
序列化方法如下:
zmq::message_t request(_msg.ByteSize());
std::string value = _msg.SerializeAsString();
memcpy(request.data(), reinterpret_cast<const void*>(value.c_str()), value.size());
return request;
和set_probed_value()
看起来像这样:
void set_probed_value(const double& val)
{
_msg.clear_probed();
_msg.set_probed(val);
}
我知道当我将 probed 的值设置为与解析时设置的值不同的数字时会导致问题。如果我删除该行 msg.set_probed_value(12.0)
,则不会发生异常,一切正常。
Assertion failed: check () (/apps/zmq/libzmq/src/msg.cpp:347)
嫌疑人?违反了 ZeroMQ API 发布的原则
众所周知,所有消息操作都非常脆弱。
先做一个显式的内容复制,而不是直接操作语法加糖的 reinterpret_cast<...>( msg.data() )
内容(由 ZeroMQ 传递的指针引用)怎么样?
Avoid modifying message content after a message has been copied with zmq_msg_copy()
, doing so can result in undefined behaviour. If what you need is an actual hard copy, allocate a new message using zmq_msg_init_size()
and copy the message content using memcpy()
.
作为已发布的 ZeroMQ API 中已发布的公平设计实践,在安全内容副本完成后,还建议 request
消息对象的显式 close()
] 强烈推荐
Never access zmq_msg_t
members directly, instead always use the zmq_msg
family of functions.
ZeroMQ API 明确警告不要尝试以任何其他方式操纵任何消息内容,而不是使用 API 发布的函数/方法.最好避免任何此类技巧,即使代价是代码更冗长和更多 SLOC-s。
您确定在该 zmq 消息中有 NULL 终止吗msg
?
_msg.ParseFromString(reinterpret_cast<const char*>(msg.data()));
否则,当它读取到您认为是字符串的末尾时,这会在您的 _msg
中填满垃圾。
我问的原因是:
当您 create/send 消息时 不包含 NULL
zmq::message_t request(_msg.ByteSize());
std::string value = _msg.SerializeAsString();
memcpy(request.data(), reinterpret_cast<const void*>(value.c_str()), value.size());
return request;
我正在测试使用 zmq 作为套接字和网络工具以及使用 protobuf 进行序列化的代码。
代码接收一个 zmq_message 并将其解析为 protobuf class,在 return 我更改其中一个 class 成员的值并发送相同的值class 返回请求者。
在此过程中,zmq 断言 check()
以某种方式失败。我真的不知道为什么会这样,因为我觉得一切都很好。
主文件中的代码如下所示:
zmq::socket_t external(context, ZMQ_REP);
external.bind("tcp://*:29067");
zmq::message_t request;
external.recv(&request);
msg.deserialize(request);
msg.set_probed_value(12.0);
zmq::message_t response = msg.serialize();
external.send(response);
反序列化方法如下所示。
_msg.ParseFromString(reinterpret_cast<const char*>(msg.data()));
序列化方法如下:
zmq::message_t request(_msg.ByteSize());
std::string value = _msg.SerializeAsString();
memcpy(request.data(), reinterpret_cast<const void*>(value.c_str()), value.size());
return request;
和set_probed_value()
看起来像这样:
void set_probed_value(const double& val)
{
_msg.clear_probed();
_msg.set_probed(val);
}
我知道当我将 probed 的值设置为与解析时设置的值不同的数字时会导致问题。如果我删除该行 msg.set_probed_value(12.0)
,则不会发生异常,一切正常。
Assertion failed: check () (/apps/zmq/libzmq/src/msg.cpp:347)
嫌疑人?违反了 ZeroMQ API 发布的原则
众所周知,所有消息操作都非常脆弱。
先做一个显式的内容复制,而不是直接操作语法加糖的 reinterpret_cast<...>( msg.data() )
内容(由 ZeroMQ 传递的指针引用)怎么样?
Avoid modifying message content after a message has been copied with
zmq_msg_copy()
, doing so can result in undefined behaviour. If what you need is an actual hard copy, allocate a new message usingzmq_msg_init_size()
and copy the message content usingmemcpy()
.
作为已发布的 ZeroMQ API 中已发布的公平设计实践,在安全内容副本完成后,还建议 request
消息对象的显式 close()
] 强烈推荐
Never access
zmq_msg_t
members directly, instead always use thezmq_msg
family of functions.
ZeroMQ API 明确警告不要尝试以任何其他方式操纵任何消息内容,而不是使用 API 发布的函数/方法.最好避免任何此类技巧,即使代价是代码更冗长和更多 SLOC-s。
您确定在该 zmq 消息中有 NULL 终止吗msg
?
_msg.ParseFromString(reinterpret_cast<const char*>(msg.data()));
否则,当它读取到您认为是字符串的末尾时,这会在您的 _msg
中填满垃圾。
我问的原因是:
当您 create/send 消息时 不包含 NULL
zmq::message_t request(_msg.ByteSize());
std::string value = _msg.SerializeAsString();
memcpy(request.data(), reinterpret_cast<const void*>(value.c_str()), value.size());
return request;