C++Boost序列化:输入流错误



各位C++开发人员,

我正试图用zmqboost::serialization通过网络发送一个C++类。

其概念是在客户端上序列化类PlayCommand。然后用zmq将其发送到服务器。并在服务器上对其进行反序列化。

这在应用程序的其余部分中运行良好。出于某种原因,我在服务器上反序列化PlayCommand时不时会收到输入流错误。我不明白为什么它有时抛出这个异常,有时却不抛出。

这似乎是一个时间敏感的问题。我是否必须等待某个时刻才能让boost发挥作用?

std::shared_ptr<PlayCommand> _exe(dynamic_cast<PlayCommand*>(_cmd.get()));

zmq::context_t _ctx(1);
zmq::socket_t _skt(_ctx, ZMQ_PUB);
_skt.connect("tcp://0.0.0.0:" + this->kinect_daemon_com_port);
std::stringstream _type_stream;
std::stringstream _exe_stream;
boost::archive::text_oarchive _type_archive(_type_stream);
boost::archive::text_oarchive _exe_archive(_exe_stream);
_type_archive << _type;
_exe_archive << *_exe.get();

std::string _type_msg_str = _type_stream.str();
std::string _exe_msg_str = _exe_stream.str();
zmq::message_t _type_msg(_type_msg_str.length());
zmq::message_t _exe_msg(_exe_msg_str.length());

memcpy(_type_msg.data(), _type_msg_str.data(), _type_msg_str.length());
memcpy(_exe_msg.data(), _exe_msg_str.data(), _exe_msg_str.length());
_skt.send(_type_msg, ZMQ_SNDMORE);
_skt.send(_exe_msg, 0);
void ZMQMessageResolver::resolve_message(std::shared_ptr<Event> _event, unsigned _unique_thread_id)
{
std::cout << "ZMQMessageResolver::resolve_message(std::shared_ptr<Event> _event, unsigned _unique_thread_id)" << std::endl;

std::shared_ptr<ZMQMessageEvent> _zmq_event = std::static_pointer_cast<ZMQMessageEvent>(_event);
//(static_cast<ZMQMessageEvent*>(_event.get()));
ZMQMessageType _type;
PlayCommand _cmd;
auto _messages = _zmq_event->get_data();
auto _type_string = std::string(static_cast<char*>(_messages->front()->data()), _messages->front()->size());
auto _cmd_string = std::string(static_cast<char*>(_messages->back()->data()), _messages->back()->size());
std::stringstream _type_stream{_type_string};
std::istringstream _cmd_stream{_cmd_string};
boost::archive::text_iarchive _type_archive{_type_stream};
boost::archive::text_iarchive _cmd_archive{_cmd_stream};
std::cout << "1" << std::endl;
_type_archive >> _type;
std::cout << "2" << std::endl;
_cmd_archive & _cmd;
std::cout << "3" << std::endl;
std::shared_ptr<ThreadEvent> _thread_event = std::make_shared<ThreadEvent>(_zmq_event->get_event_message());
_cmd.execute(_thread_event);
std::lock_guard<std::mutex> _lock{*this->thread_mutex};
this->finished_threads.push_back(_unique_thread_id);
}

完整的项目在github上:rgbd-calib和rgbd-calib-py。重要的文件是rgbd calib中的/framework/ZMQMessageResolver.cpp和rgbd calib-py中的/src/KinectDaemon.cpp。

如果有任何帮助,我将不胜感激。

第一个见解我检查了共享的zmq::socket_t实例。我找不到任何这样的线程安全应该是一个非问题。

我发现其他开发人员也遇到了ZMQ多部分消息的问题。也许这对我来说也是一个问题。也许有人是有经验的。发送和接收多部分信息时,我是否必须采取任何安全措施?

如果它对时间敏感,毫无疑问它与boost无关:显示的boost代码是完全同步和本地的。如果你不总是收到完整的流,你会得到这个错误。同样,如果在解释接收到的数据时出现协议错误,您可能会得到损坏的数据。

这两种情况都很容易导致"输入流错误"。

我没有0MQ的经验,所以我不知道所示的代码是否会收到不完整的消息,但我会调查一下。


一个次要的注意事项是,有一个stringstream和另一个istringstream是相当奇怪的。寻求行为可能存在差异

让我在故事的ZeroMQ部分加上几美分:

事实#1:
ZeroMQ从不传递垃圾
它要么传递完整的消息(发送时),要么什么都不传递

这个主要的设计特性有助于解决所声称的潜在问题之一。

如果一个应用程序确实收到了一个ZeroMQ消息,那么可以确信它是从远程进程发出的消息的形状和声音副本。这是完全一样的。止动器。

事实#2:
ZeroMQ架构师和传道者自ZeroMQ API v2.xx开始以来,在每一章中都会
警告永远不要共享

从上面描述的代码来看,这似乎是不清楚的。

如果实例化ZeroMQ套接字访问点(在上述上下文中为SUB类型),则拥有该访问点资源的线程是唯一可以使用该资源进行操作的线程,并且永远不会"让"任何其他线程接触该玩具。从不虽然最近可能会有一些关于重新设计ZeroMQ核心的讨论和努力,以增加线程安全性,但我仍然对这些举措持怀疑态度,主要是确信分布式计算中的非阻塞高性能+低延迟驱动的设计永远不应该共享一个共同的部分,是的,因为开销的成本和失去的主要安全性(这不容易通过任何线程间信令/锁定/阻塞在事后回购)。

您可以查看代码,以确认或拒绝任何类型的共享ZeroMQ实例(Context是另一个单独的主题),对于检测到共享片段的情况,您的团队应该重新设计代码以避免它。

是的。避免共享,ZeroMQ工具会把你当成地狱。

最新更新