Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
like image 320
flamenco Avatar asked May 25 '14 13:05

flamenco


People also ask

What is Python ZMQ?

ZeroMQ (also spelled ØMQ, 0MQ or ZMQ) is a high-performance asynchronous messaging library, aimed at use in distributed or concurrent applications. It provides a message queue, but unlike message-oriented middleware, a ZeroMQ system can run without a dedicated message broker.

What is ZeroMQ used for?

ZeroMQ provides a whole slew of language APIs which run on most operating systems and allows you to communicate seamlessly between all sorts of programs. It also provides a collection of patterns, such as request-reply and publish-subscribe which assist you in creating and structuring your network.

What is a ZMQ server?

The ZMQ framework (actually ØMQ) is used to interconnect applications or parts of applications to other applications via a range of interfaces. It's really nice since there's lots of language support and it's easy to use. The application uses 4 ports for communicating: 2000: Main command/response socket (server/client)

What is ZMQ socket?

ZeroMQ (also known as ØMQ, 0MQ, or zmq) looks like an embeddable networking library but acts like a concurrency framework. It gives you sockets that carry atomic messages across various transports like in-process, inter-process, TCP, and multicast.


1 Answers

Here is the solution that I came up with...just in case someday, someone might need help with a similar situation. The idea is to packetize all lines in one single message and send it back to client. It seems that the it works is that for every request made by client , the server needs to make a reply and only one reply. At least that's how I see it..

Replace code on the server side

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

with:

#  Send reply back to client
with open("test.txt", 'r') as f:
    message = '%s' % f.readlines()
    print(message)
    print(type(message))
    socket.send_string(message)

Client request

Connecting to hello world server
Sending request 0
Received reply 0 [ ['This is test line 1\n', 'This is test line 2\n', 'This is test line 3\n', 'This is test line 4\n', 'This is test line 5\n', 'This is test line 6\n', 'This is test line 7\n', 'This is test line 8\n', 'This is test line 9\n', 'This is test line 10\n', '\n'] ]
Sending request 1
Received reply 1 [ ['This is test line 1\n', 'This is test line 2\n', 'This is test line 3\n', 'This is test line 4\n', 'This is test line 5\n', 'This is test line 6\n', 'This is test line 7\n', 'This is test line 8\n', 'This is test line 9\n', 'This is test line 10\n', '\n'] ]
 ....
 ....
 and so on up to 10 requests

Server response

Received request: Hello
['This is test line 1\n', 'This is test line 2\n', 'This is test line 3\n', 'This is test line 4\n', 'This is test line 5\n', 'This is test line 6\n', 'This is test line 7\n', 'This is test line 8\n', 'This is test line 9\n', 'This is test line 10\n', '\n']
<type 'str'>
Received request: Hello
['This is test line 1\n', 'This is test line 2\n', 'This is test line 3\n', 'This is test line 4\n', 'This is test line 5\n', 'This is test line 6\n', 'This is test line 7\n', 'This is test line 8\n', 'This is test line 9\n', 'This is test line 10\n', '\n']
<type 'str'>
....
....
....
and so on....

Now that this is solved, the next question would be: what kind of request client needs to send to be able to accept responses from the server in line-by-line fashion. I will update the response if I will have a solution or you can feel free to participate with your own.

like image 125
flamenco Avatar answered Sep 18 '22 07:09

flamenco