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()
.