网络连接丢失时ZMQ发布-订阅程序失败

6 投票
1 回答
1865 浏览
提问于 2025-04-17 07:25

我在一个中型网络上设置了一个简单的发布-订阅系统,使用的是ZMQ 2.1。虽然有些订阅者使用的是C#,其他的则使用Python,但我遇到的问题在这两种情况下都是一样的。

如果我拔掉一个运行订阅者的机器的网络线,就会出现一个无法捕捉的错误,导致那个订阅者立刻终止。

下面是一个用Python写的非常简单的订阅者示例(这不是实际的生产代码,但足以重现问题):

import zmq

def main(server_address, port):

    context = zmq.Context()
    sub_socket = context.socket(zmq.SUB)
    sub_socket.connect("tcp://" + server_address + ":" + str(port))
    sub_socket.setsockopt(zmq.SUBSCRIBE, "KITH1S2")

    while True:

        msg = sub_socket.recv()      
        print msg  

if __name__ == "__main__": main("company-intranet", 4000)

在C#中,程序会悄无声息地终止。而在Python中,我至少能看到这个错误信息:

断言失败:rc == 0 (....\src\zmq_connector.cpp:48)

这个应用程序请求运行时以一种不寻常的方式终止它。请联系应用程序的支持团队以获取更多信息。

我尝试过非阻塞版本和轮询版本,但无论哪种情况,这个瞬间终止的问题依然存在。难道我应该做的事情有什么明显的,但我却没有做到?(也就是说,对别人来说很明显 :))。

编辑:

我发现了以下内容: https://zeromq.jira.com/browse/LIBZMQ-207

看起来这似乎是一个已知问题。

那个链接进一步指向了Github,在2.1.10的更新日志中有这样的说明:

  • 修复了问题207,在使用无效的zmq_connect()字符串或无法解析主机名时,zmq_connecter.cpp:48中的断言失败。现在在这两种情况下,zmq_connect()调用都会返回-1。

虽然connect()确实在Python中抛出了无效参数的异常(在C#中似乎没有?),但recv()仍然会失败。如果订阅者机器突然失去网络连接,那这个订阅者就会停止工作。

所以,我打算试试用IP地址代替名称地址,看看这样是否能绕过这个问题。虽然不是最理想的解决办法,但总比直接崩溃要好。

1 个回答

1

原问题:我是不是漏掉了什么明显的事情?

没有。

目前的解决办法是使用IP地址。这种方法在网络断开时不会导致ZMQ 2.1.x程序出错。

撰写回答