стандартный поток вывода с PyZMQ - PullRequest
0 голосов
/ 29 апреля 2018

У меня есть клиентское приложение, которое отправляет сообщение на удаленный сервер, сообщение обрабатывается с сервера и результат отправляется обратно клиенту.

Упрощенный пример выглядит так:

client.py

import zmq
def get_message(msg, ip, port, socket, send_socket_type='pyobj'):
    socket.connect("tcp://%s:%s" % (ip, port))
    socket.send_string(msg)
    if send_socket_type=='pyobj':
        msg = socket.recv_pyobj()
    if send_socket_type=='string':
        msg = socket.recv_string()
    if send_socket_type=='json':
        msg = socket.recv_json()
    return msg
    socket.close()

server.py

import zmq
import time

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


def processmessage(msg):
    for i in range(10):
        print(i)
        time.sleep(1)
    return msg

while True:
    msg = socket.recv()
    print('message received from client:', msg)
    cmd = processmessage(msg)
    socket.send_pyobj(cmd)
    print('sending to client: %s ' % msg)
    time.sleep(0.2)

Тестирование:

server_env={'IP': ip, 'PORT': port}

context = zmq.Context()
socket = context.socket(zmq.REQ)

messages = ['first message', 'second message', 'third message']

for i in messages:
  msg = get_message('message', ip=server_env['IP'], port=server_env['PORT'], socket)
  print(msg)

Мой вопрос:

  • Как я могу расширить этот простой пример клиент-сервер, чтобы позволить клиенту получать стандартный вывод, генерируемый процессом processmessage() на стороне сервера?

1 Ответ

0 голосов
/ 30 апреля 2018

Вы можете использовать менеджер контекста для перенаправления sys.stdout в объект StringIO при обработке сообщения:

from contextlib import contextmanager
import io
import sys

@contextmanager
def capture():
    save_stdout = sys.stdout
    sys.stdout = io.StringIO()
    try:
        yield sys.stdout
    finally:
        sys.stdout = save_stdout


def processmessage(msg):
    with capture() as stdout:
        for i in range(10):
            print(i)
            time.sleep(1)
    return {
        'reply': msg,
        'stdout': stdout.getvalue(),
    }

Использование этого диспетчера контекста позволяет вам захватывать стандартный вывод во время любого блока кода и извлекать любой вывод, полученный на стандартном выводе, через stdout.getvalue() после окончания контекста. Затем вы можете отправить ответ с двумя полями: сам результат и стандартный вывод, захваченный во время обработки.

Вы можете сделать то же самое с stderr, если вам интересно, либо:

  1. перенаправляет stderr на один и тот же объект StringIO, поэтому stdout / err объединяются вместе, или
  2. отправка stderr своему собственному объекту StringIO, если вы хотите хранить их отдельно.
...