pythonzeromqpyzmq

Simple client/server ZMQ in Python to send multiple lines per request


This is my first exposure to ZMQ under Python and I want the server to sent multiple lines when it receives a request from the client. The code that I added to the example offered by ZMQ on the server side is:

with open("test.txt", 'r') as f:
    for line in f:
        socket.send_string(line.rstrip("\n"))

The question is how to make the server send all lines or how to make the client not to send a request before server finishes sending all the lines from test.txt

Client

import zmq
context = zmq.Context()
print("Connecting to hello world server")
socket = context.socket(zmq.REQ)
socket.connect("tcp://localhost:5555")
for request in range(10):
    print("Sending request %s" % request)
    socket.send(b"Hello")
    message = socket.recv()
    print("Received reply %s [ %s ]" % (request, message))

Server

import time
import zmq

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

while True:
    #  Wait for next request from client
    message = socket.recv()
    print("Received request: %s" % message)

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

    #  Send reply back to client
    with open("test.txt", 'r') as f:
        for line in f:
            socket.send_string(line.rstrip("\n"))

Client log

Connecting to hello wolrd server
Sending request 0
Received reply 0 [ This is test line 1 ]
Sending request 1

This is where it stops, as the server generated the error shown bellow:

Server log

line 324, in send_string
     return self.send(u.encode(encoding), flags=flags, copy=copy)
File "socket.pyx", line 571, in zmq.backend.cython.socket.Socket.send (zmq/backend/cython/socket.c:5319)
File "socket.pyx", line 618, in zmq.backend.cython.socket.Socket.send (zmq/backend/cython/socket.c:5086)
File "socket.pyx", line 181, in zmq.backend.cython.socket._send_copy (zmq/backend/cython/socket.c:2081)
File "checkrc.pxd", line 21, in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/socket.c:6032)
zmq.error.ZMQError: Operation cannot be accomplished in current state

Process finished with exit code 1 

test.txt

This is test line 1
This is test line 2
This is test line 3
This is test line 4
This is test line 5

Solution

  • Well, you came up with my preferred solution, that is, to just send the whole thing as a single message, using separate frames if necessary. That said, the reason it will allow you to only send a single reply is because you're using a REQ-REP socket pair and when using such a pair you must follow a simple "request-reply-request-reply" pattern. Each communication must start with one request, and the next message must be one reply, and the next one request, etc.

    To work around this you have several options: