socketserver.md
1> **Источник:** https://python-all.ru/3.5/library/socketserver.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 21.21. [`socketserver`](https://python-all.ru/3.5/library/socketserver.html#module-socketserver) – Каркас для сетевых серверов89**Исходный код:** [Lib/socketserver.py](https://python-all.ru/src/3.5/Lib/socketserver.py)1011---1213Модуль [`socketserver`](https://python-all.ru/3.5/library/socketserver.html#module-socketserver) упрощает создание сетевых серверов.1415Существует четыре базовых конкретных класса серверов:1617#### `class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)`1819Использует протокол TCP (Internet), который обеспечивает непрерывные потоки данных между клиентом и сервером. Если *bind\_and\_activate* равен True, конструктор автоматически пытается вызвать [`server_bind()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.server_bind) и [`server_activate()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.server_activate). Остальные параметры передаются базовому классу [`BaseServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer).2021#### `class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)`2223Использует дейтаграммы – отдельные пакеты информации, которые могут приходить не по порядку или теряться при передаче. Параметры те же, что и у [`TCPServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.TCPServer).2425#### `class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)`2627#### `class socketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)`2829Эти реже используемые классы похожи на классы TCP и UDP, но используют сокеты домена Unix; они недоступны на платформах, отличных от Unix. Параметры те же, что и у [`TCPServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.TCPServer).3031Эти четыре класса обрабатывают запросы *синхронно*: каждый запрос должен быть завершён до того, как начнётся следующий. Это не подходит, если каждый запрос требует много времени на выполнение из-за вычислительной сложности или большого объёма возвращаемых данных, которые клиент обрабатывает медленно. Решение – создавать отдельный процесс или поток для обработки каждого запроса; классы-примеси [`ForkingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ForkingMixIn) и [`ThreadingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ThreadingMixIn) позволяют реализовать асинхронное поведение.3233Создание сервера требует нескольких шагов. Во-первых, необходимо создать класс-обработчик запросов, унаследовав его от класса [`BaseRequestHandler`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler) и переопределив его метод [`handle()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.handle); этот метод будет обрабатывать входящие запросы. Во-вторых, нужно создать экземпляр одного из серверных классов, передав ему адрес сервера и класс-обработчик запросов. Затем вызовите метод [`handle_request()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.handle_request) или [`serve_forever()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.serve_forever) объекта сервера для обработки одного или нескольких запросов. Наконец, вызовите [`server_close()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.server_close), чтобы закрыть сокет.3435При наследовании от [`ThreadingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ThreadingMixIn) для поддержки многопоточности следует явно указать, как потоки должны вести себя при резком завершении работы. Класс [`ThreadingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ThreadingMixIn) определяет атрибут *daemon\_threads*, который указывает, должен ли сервер ожидать завершения потоков. Установите этот флаг явно, если хотите, чтобы потоки работали автономно; значение по умолчанию – [`False`](https://python-all.ru/3.5/library/constants.html#False), то есть Python не завершится, пока все потоки, созданные [`ThreadingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ThreadingMixIn), не завершатся.3637Классы серверов имеют одни и те же внешние методы и атрибуты, независимо от того, какой сетевой протокол они используют.3839## 21.21.1. Примечания по созданию сервера4041В иерархии наследования пять классов, четыре из которых представляют синхронные серверы четырёх типов:4243```python44+------------+45| BaseServer |46+------------+47 |48 v49+-----------+ +------------------+50| TCPServer |------->| UnixStreamServer |51+-----------+ +------------------+52 |53 v54+-----------+ +--------------------+55| UDPServer |------->| UnixDatagramServer |56+-----------+ +--------------------+57```5859Обратите внимание, что [`UnixDatagramServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.UnixDatagramServer) является производным от [`UDPServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.UDPServer), а не от [`UnixStreamServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.UnixStreamServer) – единственное различие между IP-сервером и Unix-сервером потоков заключается в семействе адресов, которое просто повторяется в обоих классах Unix-серверов.6061#### `class socketserver.ForkingMixIn`6263#### `class socketserver.ThreadingMixIn`6465Версии с порождением процессов и потоками для каждого типа сервера можно создать с помощью этих классов-примесей. Например, [`ThreadingUDPServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ThreadingUDPServer) создаётся следующим образом:6667```python68class ThreadingUDPServer(ThreadingMixIn, UDPServer):69 pass70```7172Класс-примесь указывается первым, поскольку он переопределяет метод, определённый в [`UDPServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.UDPServer). Установка различных атрибутов также изменяет поведение базового механизма сервера.7374#### `class socketserver.ForkingTCPServer`7576#### `class socketserver.ForkingUDPServer`7778#### `class socketserver.ThreadingTCPServer`7980#### `class socketserver.ThreadingUDPServer`8182Эти классы предварительно определены с использованием примесных классов.8384Чтобы реализовать службу, необходимо создать класс, наследующий от [`BaseRequestHandler`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler), и переопределить его метод [`handle()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.handle). Затем можно запускать различные версии службы, комбинируя один из классов сервера с классом обработчика запросов. Класс обработчика запросов должен различаться для служб датаграмм и потоков. Эту сложность можно скрыть, используя подклассы обработчиков [`StreamRequestHandler`](https://python-all.ru/3.5/library/socketserver.html#socketserver.StreamRequestHandler) или [`DatagramRequestHandler`](https://python-all.ru/3.5/library/socketserver.html#socketserver.DatagramRequestHandler).8586Конечно, нужно подходить с умом. Например, нет смысла использовать сервер с порождением процессов (forking), если служба хранит состояние в памяти, которое может изменяться разными запросами, потому что изменения в дочернем процессе никогда не попадут в исходное состояние, хранящееся в родительском процессе и передаваемое каждому дочернему. В этом случае можно использовать потоковый сервер (threading), но, скорее всего, придётся использовать блокировки для защиты целостности общих данных.8788С другой стороны, если создаётся HTTP-сервер, где все данные хранятся внешне (например, в файловой системе), синхронный класс фактически сделает службу «глухой» на время обработки одного запроса – что может занять очень много времени, если клиент медленно получает все запрошенные данные. Здесь подойдёт потоковый сервер или сервер с порождением процессов.8990В некоторых случаях может быть уместно обработать часть запроса синхронно, но завершить обработку в порождённом дочернем процессе в зависимости от данных запроса. Этого можно добиться, используя синхронный сервер и выполняя явный fork (порождение процесса) в методе [`handle()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.handle) класса обработчика запросов.9192Другой подход к обработке нескольких одновременных запросов в среде, которая не поддерживает ни потоки, ни [`fork()`](https://python-all.ru/3.5/library/os.html#os.fork) (или когда они слишком дороги или неподходящи для сервиса) – поддерживать явную таблицу частично выполненных запросов и использовать [`selectors`](https://python-all.ru/3.5/library/selectors.html#module-selectors) для решения, какой запрос обрабатывать следующим (или обрабатывать ли новый входящий запрос). Это особенно важно для потоковых сервисов, где каждый клиент потенциально может быть подключён долгое время (если потоки или подпроцессы не могут быть использованы). Смотрите [`asyncore`](https://python-all.ru/3.5/library/asyncore.html#module-asyncore) для другого способа управления этим.9394## 21.21.2. Объекты сервера9596#### `class socketserver.BaseServer(server_address, RequestHandlerClass)`9798Это суперкласс для всех объектов Server в модуле. Он определяет интерфейс, приведенный ниже, но не реализует большинство методов – это делается в подклассах. Два параметра хранятся в соответствующих атрибутах [`server_address`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.server_address) и [`RequestHandlerClass`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.RequestHandlerClass).99100#### `fileno()`101102Возвращает целочисленный файловый дескриптор сокета, на котором сервер прослушивает соединения. Эта функция чаще всего передается в [`selectors`](https://python-all.ru/3.5/library/selectors.html#module-selectors), чтобы обеспечить мониторинг нескольких серверов в одном процессе.103104#### `handle_request()`105106Обрабатывает один запрос. Эта функция вызывает следующие методы по порядку: [`get_request()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.get_request), [`verify_request()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.verify_request) и [`process_request()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.process_request). Если предоставленный пользователем метод [`handle()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.handle) класса-обработчика вызывает исключение, вызывается метод [`handle_error()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.handle_error) сервера. Если в течение [`timeout`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.timeout) секунд не поступило ни одного запроса, будет вызван [`handle_timeout()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.handle_timeout), и [`handle_request()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.handle_request) завершится.107108#### `serve_forever(poll_interval=0.5)`109110Обрабатывает запросы до явного запроса [`shutdown()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.shutdown). Опрашивает завершение каждые *poll\_interval* секунд. Игнорирует атрибут [`timeout`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.timeout). Также вызывает [`service_actions()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.service_actions), который может использоваться подклассом или миксином для предоставления действий, специфичных для данной службы. Например, класс [`ForkingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ForkingMixIn) использует [`service_actions()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.service_actions) для очистки процессов-зомби.111112Изменено в версии 3.3: Добавлен вызов `service_actions` в метод `serve_forever`.113114#### `service_actions()`115116Вызывается в цикле [`serve_forever()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.serve_forever). Этот метод может быть переопределен подклассами или классами-миксинами для выполнения действий, специфичных для данной службы, например, действий по очистке.117118Новое в версии 3.3.119120#### `shutdown()`121122Дайте команду [`serve_forever()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.serve_forever) циклу остановиться и ждать завершения.123124#### `server_close()`125126Выполняет очистку сервера. Может быть переопределен.127128#### `address_family`129130Семейство протоколов, к которому принадлежит сокет сервера. Типичные примеры – [`socket.AF_INET`](https://python-all.ru/3.5/library/socket.html#socket.AF_INET) и [`socket.AF_UNIX`](https://python-all.ru/3.5/library/socket.html#socket.AF_UNIX).131132#### `RequestHandlerClass`133134Класс обработчика запросов, предоставленный пользователем; экземпляр этого класса создаётся для каждого запроса.135136#### `server_address`137138Адрес, на котором сервер прослушивает соединения. Формат адресов меняется в зависимости от семейства протоколов; подробнее см. документацию модуля [`socket`](https://python-all.ru/3.5/library/socket.html#module-socket). Для интернет-протоколов это кортеж, содержащий строку с адресом и целое число – номер порта: например, `('127.0.0.1', 80)`.139140#### `socket`141142Объект сокета, через который сервер будет принимать входящие запросы.143144Классы серверов поддерживают следующие переменные класса:145146#### `allow_reuse_address`147148Определяет, разрешает ли сервер повторное использование адреса. По умолчанию [`False`](https://python-all.ru/3.5/library/constants.html#False); значение можно изменить в подклассах, чтобы задать другую политику.149150#### `request_queue_size`151152Размер очереди запросов. Если обработка одного запроса занимает много времени, запросы, поступающие, пока сервер занят, помещаются в очередь – до [`request_queue_size`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.request_queue_size) запросов. Когда очередь заполняется, дальнейшие запросы от клиентов получают ошибку «Connection denied». Обычно значение по умолчанию – 5, но его можно переопределить в подклассах.153154#### `socket_type`155156Тип сокета, используемый сервером; распространённые значения: [`socket.SOCK_STREAM`](https://python-all.ru/3.5/library/socket.html#socket.SOCK_STREAM) и [`socket.SOCK_DGRAM`](https://python-all.ru/3.5/library/socket.html#socket.SOCK_DGRAM).157158#### `timeout`159160Длительность тайм-аута в секундах или [`None`](https://python-all.ru/3.5/library/constants.html#None), если тайм-аут не нужен. Если [`handle_request()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.handle_request) не получает входящих запросов в течение периода тайм-аута, вызывается метод [`handle_timeout()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.handle_timeout).161162Существуют различные методы сервера, которые можно переопределить в подклассах базовых классов серверов, например [`TCPServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.TCPServer); эти методы не предназначены для внешних пользователей объекта сервера.163164#### `finish_request()`165166Непосредственно обрабатывает запрос, создавая экземпляр [`RequestHandlerClass`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.RequestHandlerClass) и вызывая его метод [`handle()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.handle).167168#### `get_request()`169170Должен принять запрос из сокета и вернуть кортеж из двух элементов, содержащий *новый* объект сокета для взаимодействия с клиентом и адрес клиента.171172#### `handle_error(request, client_address)`173174Эта функция вызывается, если метод [`handle()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.handle) экземпляра [`RequestHandlerClass`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.RequestHandlerClass) вызывает исключение. Действие по умолчанию – вывод трассировки в стандартный вывод и продолжение обработки последующих запросов.175176#### `handle_timeout()`177178Эта функция вызывается, когда атрибут [`timeout`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.timeout) установлен в значение, отличное от [`None`](https://python-all.ru/3.5/library/constants.html#None), и период тайм-аута истёк без получения запросов. По умолчанию для серверов с порождением процессов (forking) собирается статус завершившихся дочерних процессов; в многопоточных серверах этот метод ничего не делает.179180#### `process_request(request, client_address)`181182Вызывает [`finish_request()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.finish_request) для создания экземпляра [`RequestHandlerClass`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseServer.RequestHandlerClass). При необходимости эта функция может создать новый процесс или поток для обработки запроса; так поступают классы [`ForkingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ForkingMixIn) и [`ThreadingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ThreadingMixIn).183184#### `server_activate()`185186Вызывается конструктором сервера для активации сервера. По умолчанию для TCP-сервера просто вызывает [`listen()`](https://python-all.ru/3.5/library/socket.html#socket.socket.listen) на сокете сервера. Можно переопределить.187188#### `server_bind()`189190Вызывается конструктором сервера для привязки сокета к нужному адресу. Можно переопределить.191192#### `verify_request(request, client_address)`193194Должна возвращать логическое значение; если значение равно [`True`](https://python-all.ru/3.5/library/constants.html#True), запрос будет обработан, а если [`False`](https://python-all.ru/3.5/library/constants.html#False), запрос будет отклонен. Эта функция может быть переопределена для реализации контроля доступа к серверу. Реализация по умолчанию всегда возвращает [`True`](https://python-all.ru/3.5/library/constants.html#True).195196## 21.21.3. Объекты-обработчики запросов197198#### `class socketserver.BaseRequestHandler`199200Это суперкласс всех объектов-обработчиков запросов. Он определяет интерфейс, приведенный ниже. Конкретный подкласс обработчика запросов должен определить новый метод [`handle()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.handle) и может переопределять любые другие методы. Новый экземпляр подкласса создается для каждого запроса.201202#### `setup()`203204Вызывается перед методом [`handle()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.handle) для выполнения необходимых действий по инициализации. Реализация по умолчанию ничего не делает.205206#### `handle()`207208Эта функция должна выполнять всю работу, необходимую для обслуживания запроса. Реализация по умолчанию ничего не делает. Ей доступны несколько атрибутов экземпляра: запрос доступен как `self.request`; адрес клиента как `self.client_address`; а экземпляр сервера как `self.server`, на случай, если потребуется доступ к информации, специфичной для сервера.209210Тип `self.request` различается для служб дейтаграмм и потоков. Для потоковых служб `self.request` – это объект сокета; для служб дейтаграмм `self.request` – это пара из строки и сокета.211212#### `finish()`213214Вызывается после метода [`handle()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.handle) для выполнения необходимых действий по очистке. Реализация по умолчанию ничего не делает. Если [`setup()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.setup) вызывает исключение, эта функция не будет вызвана.215216#### `class socketserver.StreamRequestHandler`217218#### `class socketserver.DatagramRequestHandler`219220Эти подклассы [`BaseRequestHandler`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler) переопределяют методы [`setup()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.setup) и [`finish()`](https://python-all.ru/3.5/library/socketserver.html#socketserver.BaseRequestHandler.finish) и предоставляют атрибуты `self.rfile` и `self.wfile`. Атрибуты `self.rfile` и `self.wfile` можно соответственно читать и записывать, чтобы получить данные запроса или вернуть данные клиенту.221222## 21.21.4. Примеры223224### 21.21.4.1. [`socketserver.TCPServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.TCPServer) Пример225226Это серверная сторона:227228```python229import socketserver230231class MyTCPHandler(socketserver.BaseRequestHandler):232 """233 Класс обработчика запросов для нашего сервера.234235 Он создаётся один раз на каждое подключение к серверу и должен236 переопределять метод handle() для реализации взаимодействия с237 клиентом.238 """239240 def handle(self):241 # self.request – это TCP-сокет, подключённый к клиенту242 self.data = self.request.recv(1024).strip()243 print("{} wrote:".format(self.client_address[0]))244 print(self.data)245 # просто отправляет обратно те же данные, но в верхнем регистре246 self.request.sendall(self.data.upper())247248if __name__ == "__main__":249 HOST, PORT = "localhost", 9999250251 # Создаём сервер, привязываясь к localhost на порту 9999252 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)253254 # Запускаем сервер; он будет работать, пока вы255 # не прервёте программу с помощью Ctrl-C256 server.serve_forever()257```258259Альтернативный класс обработчика запросов, который использует потоки (объекты, подобные файлам, упрощающие взаимодействие за счет предоставления стандартного файлового интерфейса):260261```python262class MyTCPHandler(socketserver.StreamRequestHandler):263264 def handle(self):265 # self.rfile – это файлоподобный объект, созданный обработчиком;266 # теперь можно использовать, например, readline() вместо прямых вызовов recv()267 self.data = self.rfile.readline().strip()268 print("{} wrote:".format(self.client_address[0]))269 print(self.data)270 # Аналогично, self.wfile – это файлоподобный объект, используемый для записи ответа271 # клиенту272 self.wfile.write(self.data.upper())273```274275Разница в том, что вызов `readline()` во втором обработчике будет вызывать `recv()` несколько раз, пока не встретит символ новой строки, в то время как одиночный вызов `recv()` в первом обработчике просто вернет то, что было отправлено клиентом за один вызов `sendall()`.276277Это клиентская сторона:278279```python280import socket281import sys282283HOST, PORT = "localhost", 9999284data = " ".join(sys.argv[1:])285286# Создать сокет (SOCK_STREAM означает TCP-сокет)287with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:288 # Подключиться к серверу и отправить данные289 sock.connect((HOST, PORT))290 sock.sendall(bytes(data + "\n", "utf-8"))291292 # Получить данные от сервера и завершить работу293 received = str(sock.recv(1024), "utf-8")294295print("Sent: {}".format(data))296print("Received: {}".format(received))297```298299Результат работы примера должен выглядеть примерно так:300301Сервер:302303```console304$ python TCPServer.py305127.0.0.1 wrote:306b'hello world with TCP'307127.0.0.1 wrote:308b'python is nice'309```310311Клиент:312313```console314$ python TCPClient.py hello world with TCP315Sent: hello world with TCP316Received: HELLO WORLD WITH TCP317$ python TCPClient.py python is nice318Sent: python is nice319Received: PYTHON IS NICE320```321322### 21.21.4.2. [`socketserver.UDPServer`](https://python-all.ru/3.5/library/socketserver.html#socketserver.UDPServer) Пример323324Это серверная сторона:325326```python327import socketserver328329class MyUDPHandler(socketserver.BaseRequestHandler):330 """331 Этот класс работает аналогично классу-обработчику TCP, за исключением того, что332 self.request состоит из пары данных и клиентского сокета, и поскольку333 соединение отсутствует, адрес клиента должен быть указан явно334 при отправке данных обратно через sendto().335 """336337 def handle(self):338 data = self.request[0].strip()339 socket = self.request[1]340 print("{} wrote:".format(self.client_address[0]))341 print(data)342 socket.sendto(data.upper(), self.client_address)343344if __name__ == "__main__":345 HOST, PORT = "localhost", 9999346 server = socketserver.UDPServer((HOST, PORT), MyUDPHandler)347 server.serve_forever()348```349350Это клиентская сторона:351352```python353import socket354import sys355356HOST, PORT = "localhost", 9999357data = " ".join(sys.argv[1:])358359# SOCK_DGRAM – это тип сокета для UDP-сокетов360sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)361362# Как можно видеть, вызов connect() отсутствует; в UDP нет соединений.363# Вместо этого данные отправляются напрямую получателю через sendto().364sock.sendto(bytes(data + "\n", "utf-8"), (HOST, PORT))365received = str(sock.recv(1024), "utf-8")366367print("Sent: {}".format(data))368print("Received: {}".format(received))369```370371Результат работы примера должен выглядеть точно так же, как для примера TCP-сервера.372373### 21.21.4.3. Асинхронные миксины374375Для построения асинхронных обработчиков используйте классы [`ThreadingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ThreadingMixIn) и [`ForkingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ForkingMixIn).376377Пример для класса [`ThreadingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ThreadingMixIn):378379```python380import socket381import threading382import socketserver383384class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):385386 def handle(self):387 data = str(self.request.recv(1024), 'ascii')388 cur_thread = threading.current_thread()389 response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')390 self.request.sendall(response)391392class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):393 pass394395def client(ip, port, message):396 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:397 sock.connect((ip, port))398 sock.sendall(bytes(message, 'ascii'))399 response = str(sock.recv(1024), 'ascii')400 print("Received: {}".format(response))401402if __name__ == "__main__":403 # Порт 0 означает выбор произвольного неиспользуемого порта404 HOST, PORT = "localhost", 0405406 server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)407 ip, port = server.server_address408409 # Запустить поток для сервера – этот поток затем запустит один410 # дополнительный поток на каждый запрос411 server_thread = threading.Thread(target=server.serve_forever)412 # Завершить поток сервера при завершении главного потока413 server_thread.daemon = True414 server_thread.start()415 print("Server loop running in thread:", server_thread.name)416417 client(ip, port, "Hello World 1")418 client(ip, port, "Hello World 2")419 client(ip, port, "Hello World 3")420421 server.shutdown()422 server.server_close()423```424425Результат работы примера должен выглядеть примерно так:426427```console428$ python ThreadedTCPServer.py429Server loop running in thread: Thread-1430Received: Thread-2: Hello World 1431Received: Thread-3: Hello World 2432Received: Thread-4: Hello World 3433```434435Класс [`ForkingMixIn`](https://python-all.ru/3.5/library/socketserver.html#socketserver.ForkingMixIn) используется так же, за исключением того, что сервер будет порождать новый процесс для каждого запроса.436