在@Jakub Piskorz的指导下,我能够找到一个可行的解决方案。您需要将zmq标识作为每条消息的第一帧发送到外部设备。但是,使用getsockopt()时,获取zmq标识不起作用。我不确定这是ZeroMQ或我正在使用的CPP活页夹的问题。但是,我能够通过分析ZeroMQ收到的0长度消息来获取ID。
我注意到的一个重要细节是,我在每次连接后收到单个0长度消息,即单帧(无身份帧),然后是0长度连接消息,即两个帧(身份帧,然后是0长度帧)。
// init context and socket zmq::context_t zctx; zmq::socket_t zsock(zctx, ZMQ_STREAM); // connect zsock.connect(address); // get socket identity from 0-length connect message // this logic ignores any 0 length frames that may be received bool idRecv = false; zmq::message_t zid; while (true) { zmq::message_t zrecv; zsock.recv(&zrecv); if (0 < zrecv.size()) { zid.copy(&zrecv); idRecv = true; } if (false == zrecv.more() && true == idRecv) { break; } }
然后,使用 多部分消息 你需要先发送身份框架。
// send first frame zsock.send(zid, ZMQ_SNDMORE); // send next frame std::string testMsg = "test"; zmq::message_t zmsgFrameTwo(testMsg.c_str(), testMsg.size()); zsock.send(zmsgFrameTwo);
这允许消息成功通过。
最后,确保同时接收身份框架和对您的请求的回复。它们是独立的框架。
// receive identity frame zmq::message_t zrecvid; zsock.recv(&zrecvid); // receive reply frame zmq::message_t zreply; zsock.recv(&zreply);
使用ZMQ_STREAM有点棘手,但您应该能够使用单个套接字与外部TCP套接字进行通信。
一个免责声明,我将展示使用zmqpp库的示例,但关键点不是要调用的确切函数,而是如何正确应用流,所以我希望您能够将其转换为纯ZeroMQ。
看一眼 zmq api docs ,原生图案款。
要启动与远程连接,请在连接后获取ZMQ_IDENTITY。
要打开与服务器的连接,请使用zmq_connect调用,然后使用 使用ZMQ_IDENTITY zmq_getsockopt调用获取套接字标识。
zmqpp::socket tcp{context, zmqpp::socket_type::stream}; tcp.connect("tcp://127.0.0.1:12345"); std::string identity = tcp.get<std::string>(zmqpp::socket_option::identity);
什么是身份?二进制数据。从 文档 :
标识应至少为一个字节,最多为255个字节。 以二进制零开始的标识保留供?MQ使用 基础设施。
获取标识后,您可以在套接字上接收以获取零长度消息 - 它将指示已建立连接。
建立连接时,将收到零长度消息 应用程序。
的 我发现,当ZMQ_STREAM api文档提到零长度消息时,它实际上意味着具有2帧,第一个标识,第二个零长度的消息。 强>
现在,发送。您的代码中缺少的是将标识作为消息的第一帧传递。 ZeroMQ引擎将删除它并仅发送第二帧(您不能向消息添加更多帧)。
您必须发送一个标识帧,然后发送一个数据帧。该 标识帧需要ZMQ_SNDMORE标志,但会被忽略 数据帧。
zmqpp::message msg; msg << identity; msg << "Hello world"; tcp.send(msg);
现在您可以等待来自远程的响应,您将收到正确的回复(由2帧组成的消息,第一个标识,第二个,远程回答的内容)或断开连接指示(零长度消息)。
接收TCP数据时,ZMQ_STREAM套接字应在前置消息 包含消息的始发对等体的标识的部分 在将它传递给应用程序之前。 同样,当对等体断开连接(或连接丢失)时,a 应用程序将收到零长度消息。
接收TCP数据时,ZMQ_STREAM套接字应在前置消息 包含消息的始发对等体的标识的部分 在将它传递给应用程序之前。
同样,当对等体断开连接(或连接丢失)时,a 应用程序将收到零长度消息。
zmqpp::message msg; tcp.receive(msg); std::string r_ident; msg >> r_ident; std::string body; msg >> body;