Why doesn't zeromq work on localhost?
PythonLocalhostZeromqPython 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")