Zeromq与python连接无效套接字时卡住

2 投票
2 回答
4713 浏览
提问于 2025-04-17 05:14

如果我用pyzmq连接一个不存在的套接字,我需要按CTRL_C才能停止程序。有人能解释一下为什么会这样吗?

import zmq

INVALID_ADDR = 'ipc:///tmp/idontexist.socket'

context = zmq.Context()
socket = context.socket(zmq.REQ)

socket.connect(INVALID_ADDR)
socket.send('hello')

poller = zmq.Poller()
poller.register(socket, zmq.POLLIN)
conn = dict(poller.poll(1000))
if conn:
    if conn.get(socket) == zmq.POLLIN:
        print "got result: ", socket.recv(zmq.NOBLOCK)
else:
    print 'got no result'

2 个回答

0

在大多数情况下,你可以先绑定(bind)或者先连接(connect)ZMQ的套接字,顺序其实没那么重要。所以,当你调用connect()或send()的时候,它只是等着另一端的bind(),但如果那边根本没有执行bind(),程序就会看起来像是卡住了一样。你可以通过打印一些日志信息来检查程序卡住的地方...

12

这个问题也在GitHub上作为pyzmq的一个问题被提出来了。我在这里简单说一下我的解释(希望这样做是合适的,我对StackOverflow还比较陌生):

一个通用的规则是:如果你在使用zeromq程序时遇到卡住的情况,通常是因为设置了 LINGER 选项。

这里的卡住是因为 LINGER 这个套接字选项引起的,它发生在脚本最后的垃圾回收阶段,也就是调用 context.term() 方法的时候。简单来说,LINGER 的作用是设置一个超时时间(以毫秒为单位),在关闭套接字后等待队列中任何待处理的消息被处理完再丢弃这些消息。默认情况下,LINGER=-1,这意味着会一直等待下去。

在这个情况下,由于没有启动任何对等方,你尝试发送的 'hello' 消息仍然在发送队列中等待,而套接字试图关闭。因为 LINGER=-1,ZeroMQ 会一直等到有对等方准备好接收这条消息后才会关闭。如果你在这个脚本卡住的时候,将一个 REP 套接字绑定到 'ipc:///tmp/idontexist.socket',那么消息就会被发送出去,脚本也会顺利结束。

如果你不想让你的脚本等待(就像你在打印语句中表示的那样,你已经放弃了等待回复),可以把 LINGER 设置为任何非负值(例如 socket.linger = 0),这样 context.term() 就会在等待指定的毫秒数后返回。

我还要提到的是,INVALID_ADDR 这个变量名让人觉得连接到一个还没有监听的接口是不合法的——其实这是错误的。zeromq 允许绑定和连接事件以任何顺序发生,就像上面描述的那样,在发送脚本卡在 term() 的时候,仍然可以将 REP 套接字绑定到接口上。

撰写回答