Alejandro Diaz Roque
Alejandro Diaz Roque

Reputation: 67

Making many replier sockets in the server side of a ZeroMQ REQ/REP pattern, using threads

For reasons of my work, using ZeroMQ REQ/REP pattern, I decided to make the replier work of the server in a different thread from the principal. The code that I'm going to show summarize that approach:

import time
import zmq
import threading


def make_work(context):
    socket = context.socket(zmq.REP)
    socket.bind("tcp://*:5555")

    message = socket.recv()
    print("Received request: %s" % message)

    #Do some 'work'
    time.sleep(1)

    #Send reply back to client
    socket.send(b"World")
    socket.close()



 context = zmq.Context()
 thr = None

 while True:

    if not thr or not thr.is_alive():

        thr = threading.Thread(target = make_work, args = (context, ) )
        thr.start()

I modified the hello world example of the pyzmq guide. So, my problem is that when I run the hello world client from the doc made by Pieter Hintjens, the expected behavior is : for each thread that I'm creating, the replier socket that I open, sends the answer to the client, but the real behavior is, that after the first thread, both sides of the connection blocks. If I make a poll in the client side, and retry to send, it's success, but this is not that I want. It is possible a successful receive in the server side, in the new thread?

Upvotes: 2

Views: 181

Answers (1)

user3666197
user3666197

Reputation: 1

Q : It is possible a successful receive in the server side, in the new thread?

Yes, it is.

Your half of the code ( client still invisible ) suffers from very low efficiency. It takes some time to create + setup + self-establish a infrastructure ( re-instantiate a Socket-instance, configure its local side, ask O/S to provide a port for .bind(), wait for others to successfully detect a presence of a new counterparty to .connect() and actually do a .connect() to setup and negotiate a ling there and back ...), all that done for but a one message and .close()?

Well, if one wishes.

Smart systems re-use resources without paying twice, the less many times, for what has already been paid for.


Plus, your infinite-loop "re-instated" thread takes additional side-effects you do not see from the code. Besides all the above sketched systematic ( yet each call re-repeated ) delays, there is one more, potentially forever blocking delay - the zmq.LINGER - a secret blocker.

Early versions of the ZeroMQ API worked with a default of zmq.LINGER == -1 - being able to block inifitely long on the .close() method. More recent versions, the v4.3-stable for sure, use a zmq.LINGER default of 1000 [ms].

Anyway, a professional design explicitly controls the instance parameters and sets the .setsockopt( zmq.LINGER, 0 ) for safety purposes always and without exception.

If interested, feel free to read more details about other silent dangers of the REQ/REP mutual deadlocks in many other ZeroMQ posts

Upvotes: 1

Related Questions