为什么zeromq在localhost上不起作用?

75 投票
2 回答
40580 浏览
提问于 2025-04-16 17:46

这段代码运行得很好:

import zmq, json, time

def main():
    context = zmq.Context()
    subscriber = context.socket(zmq.SUB)
    subscriber.bind("ipc://test")
    subscriber.setsockopt(zmq.SUBSCRIBE, '')
    while True:
        print subscriber.recv()

def main():
    context = zmq.Context()
    publisher = context.socket(zmq.PUB)
    publisher.connect("ipc://test")
    while True:
        publisher.send( "hello world" )
        time.sleep( 1 )

但是这段代码不行

import zmq, json, time

def recv():
    context = zmq.Context()
    subscriber = context.socket(zmq.SUB)
    subscriber.bind("tcp://localhost:5555")
    subscriber.setsockopt(zmq.SUBSCRIBE, '')
    while True:
        print subscriber.recv()

def send():
    context = zmq.Context()
    publisher = context.socket(zmq.PUB)
    publisher.connect("tcp://localhost:5555")
    while True:
        publisher.send( "hello world" )
        time.sleep( 1 )

它会出现这个错误:

ZMQError: 没有这样的设备

为什么,zeromq不能使用本地接口吗?

它只能在同一台机器上的IPC(进程间通信)上工作吗?

2 个回答

197

正如 @fdb 指出的:

问题出在这一行:

subscriber.bind("tcp://localhost:5555")

试着改成:

subscriber.bind("tcp://127.0.0.1:5555")

不过,这里需要更多的解释来理解原因。

zmq_bind 的文档解释道(我加粗的部分):

endpoint 参数是一个字符串,由两部分组成:transport://addresstransport 部分指定了要使用的底层传输协议。address 部分的含义取决于所选的底层传输协议。

由于你的例子使用的是 tcp 作为传输协议,我们查看 zmq_tcp 的文档,发现(同样是我加粗的部分):

当使用 zmq_bind() 为一个套接字分配本地地址时,使用 tcp 传输,endpoint 应该被理解为一个 接口,后面跟着一个冒号和要使用的 TCP 端口号。

接口可以通过以下任一方式指定:

  • 通配符 *,表示所有可用的接口。
  • 分配给接口的主要 IPv4 地址,以数字形式表示
  • 操作系统定义的接口名称。

所以,如果你不使用通配符或接口名称,那么你必须使用数字形式的 IPv4 地址(而不是 DNS 名称)。

注意,这仅适用于使用 zmq_bind!另一方面,使用 zmq_connect 时,使用 DNS 名称是完全可以的,文档中后面提到的 zmq_tcp 也说明了这一点:

当使用 zmq_connect() 将套接字连接到对等地址时,使用 tcp 传输,endpoint 应该被理解为一个对等地址,后面跟着一个冒号和要使用的 TCP 端口号。

对等地址可以通过以下任一方式指定:

  • 对等方的 DNS 名称。
  • 对等方的 IPv4 地址,以数字形式表示。
53

问题出在这一行:

subscriber.bind("tcp://localhost:5555")

试着改成:

subscriber.bind("tcp://127.0.0.1:5555")

撰写回答