Pyzmq: Connecting using source ip and port

Created on 15 Sep 2017  路  9Comments  路  Source: zeromq/pyzmq

I am trying to connect to a zmq server using a specific source IP address and port. I might misunderstand something from http://api.zeromq.org/4-1:zmq-tcp

Without a specific source ip / port, works fine:

>>> socket.connect('tcp://127.0.0.1:4506')
>>> 

But when following the syntax from the document above, it throws the error:

>>> socket.connect('tcp://172.31.11.15:17171;127.0.0.1:4506')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "zmq/backend/cython/socket.pyx", line 471, in zmq.backend.cython.socket.Socket.connect (zmq/backend/cython/socket.c:4295)
zmq.error.ZMQError: Invalid argument

Could anyone please give me a clue (I suppose this is not a bug, since I couldn't find other similar issues). Thanks!

Most helpful comment

This is unrelated to the pyzmq version. pyzmq just passes the string directly to libzmq, so the relevant version is the underlying libzmq (zmq.zmq_version()). I'm not sure what version this was introduced, but from the changelog, it looks like 4.1.6, which is included in pyzmq wheels starting with 16.0.1.

The pyzmq changelog is here, not the GitHub releases page, which is auto-generated by GitHub.

All 9 comments

Basically the easiest to test this would be following the client / server examples from http://learning-0mq-with-pyzmq.readthedocs.io/en/latest/pyzmq/patterns/pubsub.html, with the difference that the source ip / port is explicit:

server:

>>> import zmq
>>> context = zmq.Context()
>>> socket = context.socket(zmq.PUB)
>>> socket.bind('tcp://127.0.0.1:4506')

client:

>>> import zmq
>>> context = zmq.Context()
>>> socket = context.socket(zmq.SUB)
>>> socket.connect('tcp://172.31.11.15:4507;127.0.0.1:4506')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "zmq/backend/cython/socket.pyx", line 471, in zmq.backend.cython.socket.Socket.connect (zmq/backend/cython/socket.c:4295)
zmq.error.ZMQError: Invalid argument
>>> socket.connect('tcp://127.0.0.1:4506')

Hi mircea!

I think you are forgetting the subscriber.setsockopt(zmq.SUBSCRIBE, u''). You need to setup the topic.

Better try the PULL PUSH first, just to get you started. You can actually connect to multiple sources.

For your exemple, better use:
socket.connect('tcp://127.0.0.1:4506')
socket.connect('tcp://172.31.11.15:4507')

Hope this helps.

Also, have you read this http://zguide.zeromq.org/py:all .

Pieter wrote the best tutorials. May he rest in peace!

Hi @StiiCeva:

You can actually connect to multiple sources.
For your exemple, better use:
socket.connect('tcp://127.0.0.1:4506')
socket.connect('tcp://172.31.11.15:4507')

I do not intend to connect the subscriber to two publishers, but rather use a specific source IP / port combination. In the http://api.zeromq.org/4-1:zmq-tcp it is stated:

// Connecting using a IP address and bind to an IP address
rc = zmq_connect(socket, "tcp://192.168.1.17:5555;192.168.1.1:5555"); assert (rc == 0);

Hence with tcp://172.31.11.15:17171;127.0.0.1:4507 I am trying to connect to 127.0.0.1:4507 from 172.31.11.15:17171; maybe the following helps to visualise the use case: you connect the subscriber(s) from a server with many interfaces, but you have the constraint to use only one of them to reach the subscriber, which is on a different server.

Can't confirm that using other addresses.
subscriber.connect("tcp://10.42.7.5:7101;127.0.0.1:5552")
works here.

I have revisited this again, and it looks like REP-REQ sockets don't support source IP address - please let me know if my syntax is wrong, or I should discuss this upstream in the core library.

Server:

import zmq
import time
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind('tcp://127.0.0.1:49017')
while True:
    message = socket.recv()
    print("Received request: %s" % message)
    time.sleep(1)
    socket.send(b"World")

Client:

import zmq
import time
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect('tcp://127.0.0.1:49018;127.0.0.1:49017')
while True:
    socket.send(b"Hello")
    print("Sent request.")
    time.sleep(1)
    message = socket.recv()
    print("Received reply: %s" % message)

At socket.connect, the client throws:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "zmq/backend/cython/socket.pyx", line 471, in zmq.backend.cython.socket.Socket.connect (zmq/backend/cython/socket.c:4295)
zmq.error.ZMQError: Invalid argument

Is the source IP address really supported, as mentioned in the docs? Is it not supported for REQ-REP sockets? Or is it just pyzmq that doesn't support this?

Pinging @minrk - apologies for mentioning you directly - but I don't know other experts around 馃槃

Thanks!
-Mircea

Oh - found it! I was using version 14.4.0; after upgrading to 16.0.3, it worked.
@minrk mind mentioning please when this has been added? The release notes don't look extremely detailed: https://github.com/zeromq/pyzmq/releases (or I am not looking in the right place?). Thanks!

This is unrelated to the pyzmq version. pyzmq just passes the string directly to libzmq, so the relevant version is the underlying libzmq (zmq.zmq_version()). I'm not sure what version this was introduced, but from the changelog, it looks like 4.1.6, which is included in pyzmq wheels starting with 16.0.1.

The pyzmq changelog is here, not the GitHub releases page, which is auto-generated by GitHub.

That's great. Thank you very much for clarifying this @minrk!

Was this page helpful?
0 / 5 - 0 ratings