Client / Server

Request/Reply pattern

Most basic pattern is client/server model, where client sends a request and server replies to the request.

There is one difference from zmq.PAIR and other type of ZMQ sockets.

  • ZMQ REQ sockets can connect to many servers.
  • The requests will be interleaved or distributed to both the servers.

With socket zmq.PAIR, you could send any number of messages among connected peers or client/server.

  • socket zmq.REQ will block on send unless it has successfully received a reply back.
  • socket zmq.REP will block on recv unless it has received a request.

Each Request/Reply is paired and has to be successful.

../../_images/reqrep.png

reqrep_server.py

Provide port as command line argument to run server at two different ports.

import zmq
import time
import sys

port = "5556"
if len(sys.argv) > 1:
    port =  sys.argv[1]
    int(port)

Server is created with a socket type “zmq.REP” and is bound to well known port.


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

It will block on recv() to get a request before it can send a reply.

socket.bind("tcp://*:%s" % port)

while True:
    #  Wait for next request from client
    message = socket.recv()
    print "Received request: ", message
    time.sleep (1)  
    socket.send("World from %s" % port)

reqrep_client.py

Provide two ports of two different servers to connect to simultaneously.

import zmq
import sys

port = "5556"
if len(sys.argv) > 1:
    port =  sys.argv[1]
    int(port)

if len(sys.argv) > 2:
    port1 =  sys.argv[2]
    int(port1)

Client is created with a socket type “zmq.REQ”. You should notice that the same socket can connect to two different servers.

context = zmq.Context()
print "Connecting to server..."
socket = context.socket(zmq.REQ)
socket.connect ("tcp://localhost:%s" % port)
if len(sys.argv) > 2:
    socket.connect ("tcp://localhost:%s" % port1)

You have to send a request and then wait for reply.


#  Do 10 requests, waiting each time for a response
for request in range (1,10):
    print "Sending request ", request,"..."
    socket.send ("Hello")
    #  Get the reply.
    message = socket.recv()
    print "Received reply ", request, "[", message, "]"

Executing the scripts:

python reqrep_server.py 5546
python reqrep_server.py 5556
python reqrep_client.py 5546 5556

Output:

Connecting to hello world server...
Sending request  1 ...
Received reply  1 [ World from 5556 ]
Sending request  2 ...
Received reply  2 [ World from 5546 ]
Sending request  3 ...
Received reply  3 [ World from 5556 ]
Sending request  4 ...
Received reply  4 [ World from 5546 ]
Sending request  5 ...
Received reply  5 [ World from 5556 ]
Sending request  6 ...

Any attempt to send another message to the socket (zmq.REQ/zmq.REP), without having received a reply/request will result in an error:

....
socket.send ("Hello")
socket.send ("Hello1")
....

Error: zmq.core.error.ZMQError: Operation cannot be accomplished in current state

Note

If you kill the server (Ctrl-C) and restart it, the client won’t recover properly.