Search code examples
pythonrubyzeromq

ZeroMQ PAIR/PAIR connection between Ruby an Python


I want to make a simple connection between a Python program and a Ruby program using ZeroMQ, I am trying to use a PAIR connection, but I have not been able.

This is my code in python (the server):

import zmq 
import time 

port = "5553" 
context = zmq.Context() 
socket = context.socket(zmq.PAIR) 
socket.bind("tcp://*:%s" % port) 

while True: 
    socket.send(b"Server message to client3") 
    print("Enviado mensaje") 
    time.sleep(1)

It does not display anything until I connect a client.

This is the code in Ruby (the client)

require 'ffi-rzmq'
context = ZMQ::Context.new
subscriber = context.socket ZMQ::PAIR
subscriber.connect "tcp://localhost:5553"
loop do
    address = ''
    subscriber.recv_string address
    puts "[#{address}]"
end

The ruby script just freezes, it does not print anything, and the python script starts printing Enviando mensaje

B.T.W: I am using Python 3.6.9 and Ruby 2.6.5

What is the correct way to connect a zmq PAIR between Ruby and Python?


Solution

  • It does not display anything until I connect a client.

    Sure, it does not, your code imperatively asked to block until a PAIR/PAIR delivery channel got happen to become able to deliver a message. As the v4.2+ API defines, the .send()-method will block during all the duration of a "mute state".

    When a ZMQ_PAIR socket enters the mute state due to having reached the high water mark for the connected peer, or if no peer is connected, then any zmq_send(3) operations on the socket shall block until the peer becomes available for sending; messages are not discarded.

    May try non-blocking mode of sending ( always a sign of a good engineering practice to avoid blocking, the more in ) and better include also <aSocket>.close() and <aContext>.term() as a rule of thumb ( best with explicit .setsockopt( zmq.LINGER, 0 ) ) for avoiding hang-ups and as a good engineering practice to explicitly close resources and release them back to the system

    socket.send( b"Server message #[_{0:_>10d}_] to client3".format( i ), zmq.NOBLOCK )
    

    Last but not least :

    What is the correct way to connect a zmq PAIR between Ruby and Python?

    As the API documentation explains:

    ZMQ_PAIR sockets are designed for inter-thread communication across the zmq_inproc(7) transport and do not implement functionality such as auto-reconnection.

    There is no best way to do this, as Python / Ruby are not a case of inter-thread communications. ZeroMQ has since v2.1+ explicitly warned, that the PAIR/PAIR archetype is an experimental and ought be used only with bearing that in mind.

    One may always substitute each such use-case with a tandem of PUSH/PULL-simplex channels, providing the same comfort with a pair of a .send()-only + .recv()-only channels.