Сообщить об ошибке.

Классы ForkingMixIn() и ThreadingMixIn() модуля socketserver в Python

Поддержка асинхронного поведения TCP и UDP серверов

Синтаксис:

import socketserver

socketserver.ForkingMixIn
socketserver.ThreadingMixIn

Описание:

С помощью классов socketserver.ForkingMixIn и socketserver.ThreadingMixIn можно создавать каждый тип сервера, который будет обрабатывать запросы в отдельных процессах или потоках соответственно.

Например, ThreadingUDPServer создается следующим образом:

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
    pass

Первым передается смешанный класс, так как он переопределяет метод, определенный в UDPServer. Установка различных атрибутов также изменяет поведение базового механизма сервера.

Класс socketserver.ForkingMixIn доступен только на платформах POSIX, которые поддерживают функцию os.fork().

Метод класса ForkingMixIn.server_close() ожидает, пока все дочерние процессы завершаться, за исключением случаев, когда атрибут ForkingMixIn.block_on_close имеет значение False.

Метод класса ThreadingMixIn.server_close() ожидает завершения всех потоков, не являющихся демонами, за исключением случаев, когда атрибут ThreadingMixIn.block_on_close имеет значение False. Чтобы не ждать завершения потоков - используйте демонические потоки, задав для ThreadingMixIn.daemon_threads значение True.

Изменено в Python 3.7: Методы класса ForkingMixIn.server_close() и ThreadingMixIn.server_close() теперь ожидает завершения всех дочерних процессов и не демонических потоков. Добавлен новый атрибут класса ForkingMixIn.block_on_close, чтобы отказаться от поведения до версии Python 3.7.

Пример асинхронного сервера, обрабатывающего запросы в потоках:

Для создания асинхронных обработчиков необходимо использовать классы ThreadingMixIn и ForkingMixIn.

Пример для класса socketserver.ThreadingMixIn:

import socket, threading, socketserver

class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
    """Класс Обработчика клиентских запросов"""
    
    def handle(self):
        data = str(self.request.recv(1024), 'ascii')
        cur_thread = threading.current_thread()
        response = bytes(f"{cur_thread.name}: {data}", 'ascii')
        self.request.sendall(response)


class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    """
    Класс асинхронного сервера, который обрабатывает
    запросы клиентов в отдельных потоках
    """
    pass


def client(ip, port, message):
    """Функция клиента"""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect((ip, port))
        sock.sendall(bytes(message, 'ascii'))
        response = str(sock.recv(1024), 'ascii')
        print(f"Принято: {response}")


if __name__ == "__main__":
    # Порт 0 означает выбор произвольного неиспользуемого порта
    HOST, PORT = "localhost", 0
    # создаем сервер асинхронный сервер
    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    
    with server:
        ip, port = server.server_address

        # Запускаем поток с сервером - этот поток затем 
        # запустит еще один поток для каждого запроса
        server_thread = threading.Thread(target=server.serve_forever)
        # Выйдем из потока сервера, когда основной поток завершится
        server_thread.daemon = True
        server_thread.start()
        print("Серверный цикл, работающий в потоке:", server_thread.name)

        client(ip, port, "Hello World 1")
        client(ip, port, "Hello World 2")
        client(ip, port, "Hello World 3")

        server.shutdown()

Результат примера должен выглядеть примерно так:

$ python ThreadedTCPServer.py
Серверный цикл, работающий в потоке: Thread-1
Принято: Thread-2: Hello World 1
Принято: Thread-3: Hello World 2
Принято: Thread-4: Hello World 3

Класс socketserver.ForkingMixIn() используется таким же образом, за исключением того, что сервер будет порождать новый процесс для каждого запроса. Доступно только на платформах POSIX, поддерживающих функцию os.fork().