我有一个程序,其中客户端有一个ZMQ_SUB套接字,服务器端有一个ZMQ_PUB套接字,客户端订阅服务器:
非常简单的代码:
客户端:
zmq::socket_t subscriber(context, ZMQ_SUB);
subscriber.connect("tcp://xxx:xxx");
subscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0);
服务器端:
zmq::socket_t publisher(zmqContext, ZMQ_PUB);
publisher->bind("tcp://*.xxx");
我在客户端和服务器之间使用另一对ZMQ_REQ ZMQ_REP套接字。每次客户端通过ZMQ_REQ套接字向服务器发送一些请求时,服务器都会通过ZMQ_REP套接字接收它,执行一些工作,通过 REP 套接字响应,同时生成一堆消息,并通过ZMQ_PUB套接字发布它们。
大多数情况下,客户端能够从ZMQ_SUB套接字接收消息,但我确实遇到客户端无法收到这些消息的情况。
消息保证在服务器端生成,并在生成后立即发布。
正常吗?或者我的用法/设置是否有问题,导致这种不确定的行为。(客户端 SUB 套接字有时收不到消息)
正常吗?
这样的问题很容易被问到,但在没有其他细节和背景的情况下很难得到答案。
ZeroMQ
伟大的Pieter HINTJENS的书中的"丢失消息问题"一章"Code Connected Volume 1"
谈到了关于这个主题的一些一般原则:
• 在SUB
套接字上,使用zmq_setsockopt()
和ZMQ_SUBSCRIBE
设置订阅,否则您将不会收到消息。因为您按前缀订阅消息,所以如果您订阅""
(空订阅),您将获得所有内容。
• 如果在PUB
套接字开始发送数据后启动SUB
套接字(即建立与PUB
套接字的连接),您将丢失在建立连接之前发布的任何内容。如果这是一个问题,请设置您的体系结构,以便首先启动SUB
套接字,然后PUB
套接字开始发布。
• 即使您同步SUB
和PUB
套接字,您仍然可能会丢失消息。这是因为在实际创建连接之前不会创建内部队列。如果您可以切换bind
/connect
方向,使SUB
套接字bind
-s,PUB
套接字connect
-s,您可能会发现它的工作方式更符合您的预期。
• 如果您使用的是REP
和REQ
套接字,并且不遵守同步send
/recv
/send
/recv
顺序,ØMQ将报告错误,您可能会忽略这些错误。然后,看起来您正在丢失消息。如果您使用 REQ
或 REP
,请坚持 send
/recv
顺序,并始终在实际代码中检查 ØMQ 调用中的错误。
• 如果您使用的是PUSH
套接字,您会发现第一个要连接的PULL
套接字将获取不公平的消息份额。仅当所有PULL
套接字都成功连接时,才会发生消息的准确轮换,这可能需要几毫秒。作为 PUSH
/PULL
的替代方案,对于较低的数据速率,请考虑使用 ROUTER
/DEALER
和负载平衡模式。
• 如果要跨线程共享套接字,请不要这样做。它会导致随机的怪异和崩溃。
• 如果您使用的是 inproc
,请确保两个套接字位于同一context
中。否则,连接端实际上将失效。另外,先bind
,然后connect
。 inproc
不是像tcp
那样断开连接的运输。
• 如果您使用的是ROUTER
套接字,则很容易通过发送格式错误的标识框(或忘记send
标识框)意外丢失消息。通常,在ROUTER
套接字上设置ZMQ_ROUTER_MANDATORY
选项是个好主意,但也要在每次send
调用时检查返回代码。
• 最后,如果您真的无法弄清楚出了什么问题,请创建一个重现问题的最小测试用例,并向ØMQ社区寻求帮助。