Python 中的简单客户端/服务器 ZMQ,可为每个请求发送多行

fla*_*nco 5 python zeromq pyzmq

这是我第一次接触 Python 下的 ZMQ,我希望服务器在收到来自客户端的请求时发送多行。我在服务器端由 ZMQ 提供的示例中添加的代码是:

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

问题是如何让服务器发送所有行,或者如何让客户端在服务器完成发送所有行之前不发送请求 test.txt

客户

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))
Run Code Online (Sandbox Code Playgroud)

服务器

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"))
Run Code Online (Sandbox Code Playgroud)

客户端日志

Connecting to hello wolrd server
Sending request 0
Received reply 0 [ This is test line 1 ]
Sending request 1
Run Code Online (Sandbox Code Playgroud)

这是它停止的地方,因为服务器生成了如下所示的错误:

服务器日志

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 
Run Code Online (Sandbox Code Playgroud)

测试.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
Run Code Online (Sandbox Code Playgroud)

fla*_*nco 6

这是我想出的解决方案……以防万一,有人在类似情况下可能需要帮助。这个想法是将所有行打包成一条消息并将其发送回客户端。似乎它的工作原理是对于客户端发出的每个请求,服务器都需要做出回复并且只有一个回复。至少我是这么看的。。

在服务器端替换代码

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

和:

#  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)
Run Code Online (Sandbox Code Playgroud)

客户请求

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
Run Code Online (Sandbox Code Playgroud)

服务器响应

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....
Run Code Online (Sandbox Code Playgroud)

既然这已经解决了,下一个问题将是:客户端需要发送什么样的请求才能以逐行方式接受来自服务器的响应。如果我有解决方案,或者您可以随意参与,我会更新回复。


Jas*_*son 3

好吧,您提出了我首选的解决方案,即仅将整个内容作为单个消息发送,必要时使用单独的帧。也就是说,它允许您只发送单个回复的原因是因为您使用的是REQ-REP套接字对,并且在使用这样的套接字对时,您必须遵循简单的“请求-回复-请求-回复”模式。每次通信必须以一个请求开始,下一条消息必须是一个回复,然后是下一个请求,依此类推。

要解决此问题,您有多种选择:

  • 正如您所做的那样,将您想要发送的所有内容打包在一条消息中。在您的情况下,只要不存在阻止它的约束,这将是首选选项,因为所有数据实际上都是一条逻辑消息,来自一个逻辑文件,并且全部将被组合成一个逻辑块我认为接收端的数据。
  • 如果您想保留REQ-REP套接字对,那么您可以发送一个请求,然后回复,然后您的下一个请求可以是“MORE”或类似的内容,然后是下一条数据,然后继续请求“更多”,直到您的客户回复“完成”之类的内容,此时您知道您拥有所有数据并且可以停止请求更多数据。
  • 或者,如果您希望能够对单个请求进行多次回复,或者在收到回复之前多次请求,那么您将需要使用套接字ROUTER-DEALER对而不是REQ-REP. 在这种情况下,您的DEALER套接字将取代您的REQ套接字,并ROUTER取代REP. 如果您在如何实施方面遇到困难,请查看手册并提出新问题ROUTER-DEALER