Why doesn't zeromq work on localhost?

PythonLocalhostZeromq

Python Problem Overview


This code works great:

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 )

But this code doesn't* work:

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 )

It raises this error: > ZMQError: No such device

Why, can't zeromq use localhost interfaces?

Does it only work on IPC on the same machine?

Python Solutions


Solution 1 - Python

As @fdb points out:

The problem is at line:

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

try to change to:

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

However this deserves more explanation to understand why.

The documentation for zmq_bind explains (bold emphasis mine):

> The endpoint argument is a string consisting of two parts as follows: > transport://address. The transport part specifies the underlying > transport protocol to use. The meaning of the address part is specific > to the underlying transport protocol selected.

Since your example uses tcp as the transport protocol we look in the zmq_tcp documentation to discover (again, bold emphasis mine):

> When assigning a local address to a socket using zmq_bind() with the > tcp transport, the endpoint shall be interpreted as an interface > followed by a colon and the TCP port number to use. > > An interface may be specified by either of the following: > > - The wild-card *, meaning all available interfaces. > - The primary IPv4 address assigned to the interface, in its numeric representation. > - The interface name as defined by the operating system.

So, if you're not using wild-card or the interface name, then it means you must use an IPv4 address in numeric form (not a DNS name).

Note, this only applies to the use of zmq_bind! On the other hand it is perfectly fine to use a DNS name with zmq_connect as discussed later in the docs for zmq_tcp:

> When connecting a socket to a peer address using zmq_connect() with > the tcp transport, the endpoint shall be interpreted as a peer address > followed by a colon and the TCP port number to use. > > A peer address may be specified by either of the following: > > - The DNS name of the peer. > - The IPv4 address of the peer, in its numeric representation.

Solution 2 - Python

The problem is at line:

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

try to change to:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser756428View Question on Stackoverflow
Solution 1 - PythonaculichView Answer on Stackoverflow
Solution 2 - PythonfdbView Answer on Stackoverflow