如果设置 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;