Почему zeromq не работает на локальном хосте?

Этот код отлично работает:

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 на той же машине?


person user756428    schedule 16.05.2011    source источник


Ответы (2)


Проблема в строке:

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

попробуйте изменить на:

subscriber.bind("tcp://127.0.0.1:5555")
person fdb    schedule 16.05.2011
comment
Мне нравится использовать более высокий адрес, например 127.0.0.101, и изменять его для каждого приложения. Чище, чем сокеты IPC. - person Michael Dillon; 01.07.2011
comment
@fdb Да, это решает проблему, но не объясняет почему! Требуется дополнительное объяснение. - person aculich; 22.01.2012

Как указывает @fdb:

Проблема в строке:

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

попробуйте изменить на:

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

Однако это заслуживает большего объяснения, чтобы понять, почему.

Документация для zmq_bind объясняет (выделено мной жирным шрифтом):

Аргумент конечная точка представляет собой строку, состоящую из двух следующих частей: transport://address. Часть transport определяет используемый транспортный протокол. Значение части address зависит от выбранного базового транспортного протокола.

Поскольку в вашем примере в качестве транспортного протокола используется tcp, мы смотрим в документацию zmq_tcp, чтобы обнаружить (опять же, мой жирный акцент):

При назначении локального адреса сокету с помощью zmq_bind() с транспортом tcp конечная точка должна интерпретироваться как интерфейс, за которым следует двоеточие. и номер порта TCP для использования.

Интерфейс может быть указан одним из следующих способов:

  • Подстановочный знак * означает все доступные интерфейсы.
  • Основной IPv4-адрес, назначенный интерфейсу, в числовом представлении.
  • Имя интерфейса, определенное операционной системой.

Таким образом, если вы не используете подстановочный знак или имя интерфейса, это означает, что вы должны использовать адрес IPv4 в числовой форме (а не имя DNS).

Обратите внимание, это относится только к использованию zmq_bind! С другой стороны, вполне нормально использовать DNS-имя с zmq_connect, как описано ниже в документации для zmq_tcp:

При подключении сокета к одноранговому адресу с помощью zmq_connect() с транспортом tcp конечная точка должна интерпретироваться как одноранговый адрес, за которым следует двоеточие и номер TCP-порта для использования.

Одноранговый адрес может быть указан одним из следующих способов:

  • DNS-имя партнера.
  • IPv4-адрес однорангового узла в числовом представлении.
person aculich    schedule 22.01.2012
comment
Это странная реализация. - person huggie; 07.12.2014
comment
Ах, неортогональный API - person RichardOD; 12.06.2017
comment
Это связано с базовым API сокетов, который требует привязки к определенному сетевому интерфейсу (или ко всем интерфейсам) и интерфейсу имени хоста, не являющемуся сопоставлением 1-к-1. И наоборот, создание подключения к хосту с несколькими адресами — это четко определенная операция. - person joshperry; 17.05.2020