【发布时间】:2014-12-20 20:32:36
【问题描述】:
我刚刚在 Unbutu Precise (12.04) 系统上下载并安装了 zeromq-4.0.5。我已经编译了用 C 编写的 hello-world client (REQ, connect, 127.0.0.1) 和 server (REP, bind) .
- 我启动服务器。
- 我启动客户端。
- 客户端每秒向服务器发送一条消息并接收响应。
- 我按 Ctrl-C 停止服务器。
- 客户端尝试发送下一条传出消息,但它陷入了一个永不返回的 epoll 系统调用(如 strace 所示)。
- 我重新启动服务器。
- 客户端中的
zmq_recv调用仍然卡住,即使新服务器已经运行了一分钟。为客户端取得进展的唯一方法是杀死它(使用 Ctrl-C)并重新启动它。
Q1:这是预期的行为吗?我希望客户端在几秒钟内应该弄清楚服务器是再次运行,它会自动重新连接。
Q2:我应该在示例代码中更改什么来解决这个问题?
Q3:是我使用了错误的软件版本,还是我的系统出了问题?
我已禁用防火墙,sudo iptables -S 打印 -P INPUT ACCEPT; -P FORWARD ACCEPT; -P OUTPUT ACCEPT.
在strace -f ./hwclient 输出中,我可以看到客户端在服务器关闭后每秒尝试connect() 10 次(默认值ZMQ_RECONNECT_IVL)。在strace -f ./hwserver 输出上,我可以看到重新启动的服务器accept()s 连接。然而,在那之后通信就卡住了,服务器永远不会收到来自客户端的实际请求(但是当我杀死客户端时它会注意到;服务器也会收到来自服务器重启后已启动的其他客户端的请求)。
使用ipc:// 而不是tcp:// 会导致相同的行为。
如果在客户端执行下一个zmq_send 之前服务器已被终止,则自动重新连接在zmq_send 中成功发生。但是,当服务器在客户端运行 zmq_recv 时被杀死,zmq_recv 会无限期阻塞,客户端似乎无法从中恢复。
我找到了this article,它建议使用超时。但是,我认为超时不是正确的解决方案,因为 TCP 断开连接通知已经在客户端进程中可用,并且它已经在作用于它——它只是不会让 zmq_recv 重新发送请求到新的服务器 -- 或至少提前返回指示错误。
【问题讨论】:
-
检查
zmq_setsockopt和zmq_getsockopt可能会有所帮助,有一些重新连接的选项。 -
@raison:看起来
zmq_setsockopt(api.zeromq.org/4-0:zmq-setsockopt) 中ZMQ_RECONNECT_IVL的默认值启用了自动重新连接。我还应该改变什么? -
ZeroMQ 建议将所有代码设计成能够优雅地退出并释放所有资源。
SIG_KILL不会给.close()所有 ZMQ-Sockets 和.term()所有与进程相关的 ZMQ-Context 线程提供太多机会( s),如果不小心处理,历史上会导致严重的内存泄漏和 O/S 僵尸阻塞端口以及许多生产级环境问题。 -
仅供参考,我刚刚注意到这个关于可靠 REQ-REP 的非常长的章节:zguide.zeromq.org/page:all#reliable-request-reply