параллельные сокетные соединения Python - PullRequest
1 голос
/ 09 мая 2019

Я пишу базовое клиент-серверное приложение. Вот оно.

Сервер:

import socket
from multiprocessing import Process


def process_request(conn, addr):
    print('connected client:', addr)
    with conn:
        while True:
            data = conn.recv(1024)
            if not data:
                break
            print(data.decode('utf8'))


if __name__ == '__main__':
    with socket.socket() as sock:
        sock.bind(('', 10001))
        sock.listen()
        while True:
            conn, addr = sock.accept()
            p = Process(target = process_request, args = (conn, addr))
            print('starting new process')
            p.start()
            p.join()

Клиент:

import socket
from time import sleep
from multiprocessing import Pool


def create_socket_and_send_data(number):
    print(f'start sending data for {number}')

    with socket.create_connection(('127.0.0.1', 10001)) as sock:
        try:
            sock.sendall(f'sending data from {number} socket (1)\n'.encode('utf8'))
            sleep(2)
            sock.sendall(f'sending data from {number} socket (2)\n'.encode('utf8'))
        except socket.error as ex:
            print('send data error', ex)

    print(f'all data for {number} is sended')


if __name__ == '__main__':
    with Pool(processes=3) as pool:
        pool.map(create_socket_and_send_data, range(5))

Выход клиента:

$ python 59_several_connection_client.py
start sending data for 0
start sending data for 1
start sending data for 2
all data for 0 is sended
all data for 1 is sended
all data for 2 is sended
start sending data for 3
start sending data for 4
all data for 3 is sended
all data for 4 is sended

Выход сервера:

starting new process
connected client: ('127.0.0.1', 63476)
sending data from 0 socket (1)

sending data from 0 socket (2)

starting new process
connected client: ('127.0.0.1', 63477)
sending data from 1 socket (1)
sending data from 1 socket (2)

starting new process
connected client: ('127.0.0.1', 63478)
sending data from 2 socket (1)
sending data from 2 socket (2)

starting new process
connected client: ('127.0.0.1', 63479)
sending data from 3 socket (1)

sending data from 3 socket (2)

starting new process
connected client: ('127.0.0.1', 63480)
sending data from 4 socket (1)
sending data from 4 socket (2)

У меня есть несколько вопросов. Прежде всего, я не понимаю, почему последовательность вывода такая. Я думал , что это будет похоже на

data from socket 0 (1)
data from socket 1 (1)
data from socket 2 (1)
# now the pull is full, processes are sleeping
data from socket 0 (2)
data from socket 3 (1)
data from socket 1 (2)
data from socket 4 (1)
data from socket 2 (2)
# pay attention that pool had contained 3 processes, 
# it finished them one by one, so new places in the pool 
# were occupied by fresh processes that started to execute
# 
# now old 3 processes have been finished 
# and pull contains 2 new processes, they are sleeping
data from socket 4 (2)
data from socket 3 (2)
# all ok, 2 processes are done

Но неожиданно вывод получается последовательным, как будто код выполняется в одном потоке. Зачем? Может ли кто-нибудь объяснить, где разрыв в моих мыслях?

И второй крошечный вопрос: почему выходные данные иногда содержат пустые строки?

1 Ответ

1 голос
/ 09 мая 2019
  • Ты просто join() слишком рано.Ваш основной серверный процесс ждет завершения каждого сына, прежде чем создать нового, следовательно, последовательное выполнение.Для корректного выхода вы можете собирать процессы и присоединять их перед завершением выполнения вашего основного цикла.
        processes = []
        while True:
            conn, addr = sock.accept()
            p = Process(target = process_request, args = (conn, addr))
            processes.append(p) 
            print('starting new process')
            p.start()
        for p in processes:
            p.join()

Осторожно, в этом минимальном примере список processes постоянно растет.Вы можете регулярно очищать список, проверяя их exitcode.В этом случае поддержка процессов немного утомительна, поэтому я бы также предложил альтернативные способы для порождения асинхронных задач в python.

  • Пустые строки вызваны тем, что ваши пакеты заканчиваются на '\n' и print добавляет дополнительно '\n'.Таким образом, когда печатается ожидающий пакет, содержащий сообщения, он пересекает дополнительную строку.Процессы с задержкой вызова (1, 2 и 4) печатают две строки одновременно, потому что их данные буферизируются системой на стороне сервера, и печатают только один переход на две строки, тогда как другие процессы (0 и 3) печатают своивыводить построчно.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...