Документация Python неофициальный перевод

socketserver.md

445 строк · 37.1 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/2.7/library/socketserver.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 20.17. [`SocketServer`](https://python-all.ru/2.7/library/socketserver.html#module-SocketServer) – Фреймворк для сетевых серверов89> **Примечание**10>11> Модуль [`SocketServer`](https://python-all.ru/2.7/library/socketserver.html#module-SocketServer) в Python 3 переименован в `socketserver`. Инструмент [2to3](https://python-all.ru/2.7/glossary.html#term-2to3) при преобразовании исходного кода в Python 3 автоматически адаптирует импорты.1213**Исходный код:** [Lib/SocketServer.py](https://python-all.ru/src/2.7/Lib/SocketServer.py)1415---1617Модуль [`SocketServer`](https://python-all.ru/2.7/library/socketserver.html#module-SocketServer) упрощает создание сетевых серверов.1819Существует четыре базовых конкретных класса серверов:2021#### `class SocketServer.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)`2223Использует протокол TCP (Internet), который обеспечивает непрерывные потоки данных между клиентом и сервером. Если *bind\_and\_activate* равен True, конструктор автоматически пытается вызвать [`server_bind()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.server_bind) и [`server_activate()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.server_activate). Остальные параметры передаются базовому классу [`BaseServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer).2425#### `class SocketServer.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)`2627Использует дейтаграммы – отдельные пакеты информации, которые могут приходить не по порядку или теряться при передаче. Параметры те же, что и у [`TCPServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.TCPServer).2829#### `class SocketServer.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)`3031#### `class SocketServer.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)`3233Эти реже используемые классы похожи на классы TCP и UDP, но используют сокеты домена Unix; они недоступны на платформах, отличных от Unix. Параметры те же, что и у [`TCPServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.TCPServer).3435Эти четыре класса обрабатывают запросы *синхронно*: каждый запрос должен быть завершён до того, как начнётся следующий. Это не подходит, если каждый запрос требует много времени на выполнение из-за вычислительной сложности или большого объёма возвращаемых данных, которые клиент обрабатывает медленно. Решение – создавать отдельный процесс или поток для обработки каждого запроса; классы-примеси [`ForkingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ForkingMixIn) и [`ThreadingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ThreadingMixIn) позволяют реализовать асинхронное поведение.3637Создание сервера требует нескольких шагов. Во-первых, необходимо создать класс-обработчик запросов, унаследовав его от класса [`BaseRequestHandler`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler) и переопределив его метод [`handle()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.handle); этот метод будет обрабатывать входящие запросы. Во-вторых, нужно создать экземпляр одного из серверных классов, передав ему адрес сервера и класс-обработчик запросов. Затем вызовите метод [`handle_request()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.handle_request) или [`serve_forever()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.serve_forever) объекта сервера для обработки одного или нескольких запросов. Наконец, вызовите [`server_close()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.server_close), чтобы закрыть сокет.3839При наследовании от [`ThreadingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ThreadingMixIn) для многопоточного поведения соединений следует явно указать, как потоки должны вести себя при внезапном завершении. Класс [`ThreadingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ThreadingMixIn) определяет атрибут *daemon\_threads*, который указывает, должен ли сервер ожидать завершения потоков. Если требуется, чтобы потоки работали автономно, этот флаг нужно установить явно; по умолчанию [`False`](https://python-all.ru/2.7/library/constants.html#False), то есть Python не завершится, пока не завершатся все потоки, созданные [`ThreadingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ThreadingMixIn).4041Классы серверов имеют одни и те же внешние методы и атрибуты, независимо от того, какой сетевой протокол они используют.4243## 20.17.1. Заметки о создании сервера4445В иерархии наследования пять классов, четыре из которых представляют синхронные серверы четырёх типов:4647```python48+------------+49| BaseServer |50+------------+51      |52      v53+-----------+        +------------------+54| TCPServer |------->| UnixStreamServer |55+-----------+        +------------------+56      |57      v58+-----------+        +--------------------+59| UDPServer |------->| UnixDatagramServer |60+-----------+        +--------------------+61```6263Обратите внимание, что [`UnixDatagramServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.UnixDatagramServer) является производным от [`UDPServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.UDPServer), а не от [`UnixStreamServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.UnixStreamServer) – единственное различие между IP-сервером и Unix-сервером потоков заключается в семействе адресов, которое просто повторяется в обоих классах Unix-серверов.6465#### `class SocketServer.ForkingMixIn`6667#### `class SocketServer.ThreadingMixIn`6869Версии с порождением процессов и потоками для каждого типа сервера можно создать с помощью этих классов-примесей. Например, [`ThreadingUDPServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ThreadingUDPServer) создаётся следующим образом:7071```python72class ThreadingUDPServer(ThreadingMixIn, UDPServer):73    pass74```7576Класс-примесь указывается первым, поскольку он переопределяет метод, определённый в [`UDPServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.UDPServer). Установка различных атрибутов также изменяет поведение базового механизма сервера.7778[`ForkingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ForkingMixIn) и классы Forking, упомянутые ниже, доступны только на POSIX-платформах, поддерживающих [`fork()`](https://python-all.ru/2.7/library/os.html#os.fork).7980#### `class SocketServer.ForkingTCPServer`8182#### `class SocketServer.ForkingUDPServer`8384#### `class SocketServer.ThreadingTCPServer`8586#### `class SocketServer.ThreadingUDPServer`8788Эти классы предварительно определены с использованием примесных классов.8990Чтобы реализовать службу, необходимо создать класс, наследующий от [`BaseRequestHandler`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler), и переопределить его метод [`handle()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.handle). Затем можно запускать различные версии службы, комбинируя один из классов сервера с классом обработчика запросов. Класс обработчика запросов должен различаться для служб датаграмм и потоков. Эту сложность можно скрыть, используя подклассы обработчиков [`StreamRequestHandler`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.StreamRequestHandler) или [`DatagramRequestHandler`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.DatagramRequestHandler).9192Конечно, нужно подходить с умом. Например, нет смысла использовать сервер с порождением процессов (forking), если служба хранит состояние в памяти, которое может изменяться разными запросами, потому что изменения в дочернем процессе никогда не попадут в исходное состояние, хранящееся в родительском процессе и передаваемое каждому дочернему. В этом случае можно использовать потоковый сервер (threading), но, скорее всего, придётся использовать блокировки для защиты целостности общих данных.9394С другой стороны, если создаётся HTTP-сервер, где все данные хранятся внешне (например, в файловой системе), синхронный класс фактически сделает службу «глухой» на время обработки одного запроса – что может занять очень много времени, если клиент медленно получает все запрошенные данные. Здесь подойдёт потоковый сервер или сервер с порождением процессов.9596В некоторых случаях может быть уместно обработать часть запроса синхронно, но завершить обработку в порождённом дочернем процессе в зависимости от данных запроса. Этого можно добиться, используя синхронный сервер и выполняя явный fork (порождение процесса) в методе [`handle()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.handle) класса обработчика запросов.9798Другой подход к обработке нескольких одновременных запросов в среде, не поддерживающей ни потоки, ни [`fork()`](https://python-all.ru/2.7/library/os.html#os.fork) (или если они слишком дороги или неподходящи для данной услуги), – вести явную таблицу частично выполненных запросов и использовать [`select()`](https://python-all.ru/2.7/library/select.html#select.select) для выбора, над каким запросом работать дальше (или обрабатывать ли новый входящий запрос). Это особенно важно для потоковых сервисов, где каждый клиент может оставаться подключённым долгое время (если нельзя использовать потоки или подпроцессы). См. [`asyncore`](https://python-all.ru/2.7/library/asyncore.html#module-asyncore) – другой способ управления этим.99100## 20.17.2. Объекты сервера101102#### `class SocketServer.BaseServer(server_address, RequestHandlerClass)`103104Это суперкласс для всех объектов Server в модуле. Он определяет интерфейс, приведенный ниже, но не реализует большинство методов – это делается в подклассах. Два параметра хранятся в соответствующих атрибутах [`server_address`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.server_address) и [`RequestHandlerClass`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.RequestHandlerClass).105106#### `fileno()`107108Возвращает целочисленный файловый дескриптор сокета, на котором сервер прослушивает соединения. Эта функция чаще всего передается в [`select.select()`](https://python-all.ru/2.7/library/select.html#select.select), чтобы обеспечить мониторинг нескольких серверов в одном процессе.109110#### `handle_request()`111112Обрабатывает один запрос. Эта функция вызывает следующие методы по порядку: [`get_request()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.get_request), [`verify_request()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.verify_request) и [`process_request()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.process_request). Если предоставленный пользователем метод [`handle()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.handle) класса-обработчика вызывает исключение, вызывается метод [`handle_error()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.handle_error) сервера. Если в течение [`timeout`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.timeout) секунд не поступило ни одного запроса, будет вызван [`handle_timeout()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.handle_timeout), и [`handle_request()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.handle_request) завершится.113114#### `serve_forever(poll_interval=0.5)`115116Обрабатывает запросы до явного запроса [`shutdown()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.shutdown). Опрашивает завершение каждые *poll\_interval* секунд. Игнорирует атрибут [`timeout`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.timeout). Если нужно выполнять периодические задачи, делайте это в другом потоке.117118#### `shutdown()`119120Дайте команду [`serve_forever()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.serve_forever) циклу остановиться и ждать завершения.121122Новое в версии 2.6.123124#### `server_close()`125126Выполняет очистку сервера. Может быть переопределен.127128Новое в версии 2.6.129130#### `address_family`131132Семейство протоколов, к которому принадлежит сокет сервера. Типичные примеры – [`socket.AF_INET`](https://python-all.ru/2.7/library/socket.html#socket.AF_INET) и [`socket.AF_UNIX`](https://python-all.ru/2.7/library/socket.html#socket.AF_UNIX).133134#### `RequestHandlerClass`135136Класс обработчика запросов, предоставленный пользователем; экземпляр этого класса создаётся для каждого запроса.137138#### `server_address`139140Адрес, на котором сервер прослушивает соединения. Формат адресов меняется в зависимости от семейства протоколов; подробнее см. документацию модуля [`socket`](https://python-all.ru/2.7/library/socket.html#module-socket). Для интернет-протоколов это кортеж, содержащий строку с адресом и целое число – номер порта: например, `('127.0.0.1', 80)`.141142#### `socket`143144Объект сокета, через который сервер будет принимать входящие запросы.145146Классы серверов поддерживают следующие переменные класса:147148#### `allow_reuse_address`149150Определяет, разрешает ли сервер повторное использование адреса. По умолчанию [`False`](https://python-all.ru/2.7/library/constants.html#False); в подклассах можно переопределить, чтобы изменить политику.151152#### `request_queue_size`153154Размер очереди запросов. Если обработка одного запроса занимает много времени, запросы, поступающие, пока сервер занят, помещаются в очередь – до [`request_queue_size`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.request_queue_size) запросов. Когда очередь заполняется, дальнейшие запросы от клиентов получают ошибку «Connection denied». Обычно значение по умолчанию – 5, но его можно переопределить в подклассах.155156#### `socket_type`157158Тип сокета, используемый сервером; распространённые значения: [`socket.SOCK_STREAM`](https://python-all.ru/2.7/library/socket.html#socket.SOCK_STREAM) и [`socket.SOCK_DGRAM`](https://python-all.ru/2.7/library/socket.html#socket.SOCK_DGRAM).159160#### `timeout`161162Длительность тайм-аута в секундах или [`None`](https://python-all.ru/2.7/library/constants.html#None), если тайм-аут не нужен. Если [`handle_request()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.handle_request) не получает входящих запросов в течение периода тайм-аута, вызывается метод [`handle_timeout()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.handle_timeout).163164Существуют различные методы сервера, которые можно переопределить в подклассах базовых классов серверов, например [`TCPServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.TCPServer); эти методы не предназначены для внешних пользователей объекта сервера.165166#### `finish_request(request, client_address)`167168Непосредственно обрабатывает запрос, создавая экземпляр [`RequestHandlerClass`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.RequestHandlerClass) и вызывая его метод [`handle()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.handle).169170#### `get_request()`171172Должен принять запрос из сокета и вернуть кортеж из двух элементов, содержащий *новый* объект сокета для взаимодействия с клиентом и адрес клиента.173174#### `handle_error(request, client_address)`175176Эта функция вызывается, если метод [`handle()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.handle) экземпляра [`RequestHandlerClass`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.RequestHandlerClass) вызывает исключение. Действие по умолчанию – вывод трассировки в стандартный вывод и продолжение обработки последующих запросов.177178#### `handle_timeout()`179180Эта функция вызывается, когда атрибут [`timeout`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.timeout) установлен в значение, отличное от [`None`](https://python-all.ru/2.7/library/constants.html#None), и период тайм-аута истёк без получения запросов. По умолчанию для серверов с порождением процессов (forking) собирается статус завершившихся дочерних процессов; в многопоточных серверах этот метод ничего не делает.181182#### `process_request(request, client_address)`183184Вызывает [`finish_request()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.finish_request) для создания экземпляра [`RequestHandlerClass`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseServer.RequestHandlerClass). При необходимости эта функция может создать новый процесс или поток для обработки запроса; так поступают классы [`ForkingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ForkingMixIn) и [`ThreadingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ThreadingMixIn).185186#### `server_activate()`187188Вызывается конструктором сервера для активации сервера. Поведение по умолчанию для TCP-сервера просто вызывает [`listen()`](https://python-all.ru/2.7/library/socket.html#socket.socket.listen) на сокете сервера. Можно переопределить.189190#### `server_bind()`191192Вызывается конструктором сервера для привязки сокета к нужному адресу. Можно переопределить.193194#### `verify_request(request, client_address)`195196Должна возвращать логическое значение; если значение [`True`](https://python-all.ru/2.7/library/constants.html#True), запрос будет обработан, если [`False`](https://python-all.ru/2.7/library/constants.html#False) – отклонён. Эту функцию можно переопределить для реализации контроля доступа к серверу. Реализация по умолчанию всегда возвращает [`True`](https://python-all.ru/2.7/library/constants.html#True).197198## 20.17.3. Объекты обработчиков запросов199200#### `class SocketServer.BaseRequestHandler`201202Это суперкласс всех объектов-обработчиков запросов. Он определяет интерфейс, приведенный ниже. Конкретный подкласс обработчика запросов должен определить новый метод [`handle()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.handle) и может переопределять любые другие методы. Новый экземпляр подкласса создается для каждого запроса.203204#### `setup()`205206Вызывается перед методом [`handle()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.handle) для выполнения необходимых действий по инициализации. Реализация по умолчанию ничего не делает.207208#### `handle()`209210Эта функция должна выполнять всю работу, необходимую для обслуживания запроса. Реализация по умолчанию ничего не делает. Ей доступны несколько атрибутов экземпляра: запрос доступен как `self.request`; адрес клиента как `self.client_address`; а экземпляр сервера как `self.server`, на случай, если потребуется доступ к информации, специфичной для сервера.211212Тип `self.request` различается для служб дейтаграмм и потоков. Для потоковых служб `self.request` – это объект сокета; для служб дейтаграмм `self.request` – это пара из строки и сокета.213214#### `finish()`215216Вызывается после метода [`handle()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.handle) для выполнения необходимых действий по очистке. Реализация по умолчанию ничего не делает. Если [`setup()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.setup) вызывает исключение, эта функция не будет вызвана.217218#### `class SocketServer.StreamRequestHandler`219220#### `class SocketServer.DatagramRequestHandler`221222Эти подклассы [`BaseRequestHandler`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler) переопределяют методы [`setup()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.setup) и [`finish()`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.BaseRequestHandler.finish) и предоставляют атрибуты `self.rfile` и `self.wfile`. Атрибуты `self.rfile` и `self.wfile` можно соответственно читать и записывать, чтобы получить данные запроса или вернуть данные клиенту.223224## 20.17.4. Примеры225226### 20.17.4.1. [`SocketServer.TCPServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.TCPServer) Пример227228Это серверная сторона:229230```python231import SocketServer232233class MyTCPHandler(SocketServer.BaseRequestHandler):234    """235    Класс обработчика запросов для нашего сервера.236237    Он создаётся один раз на каждое подключение к серверу и должен238    переопределять метод handle() для реализации взаимодействия с239    клиентом.240    """241242    def handle(self):243        # self.request – это TCP-сокет, подключённый к клиенту244        self.data = self.request.recv(1024).strip()245        print "{} wrote:".format(self.client_address[0])246        print self.data247        # просто отправляет обратно те же данные, но в верхнем регистре248        self.request.sendall(self.data.upper())249250if __name__ == "__main__":251    HOST, PORT = "localhost", 9999252253    # Создаём сервер, привязываясь к localhost на порту 9999254    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)255256    # Запускаем сервер; он будет работать, пока вы257    # не прервёте программу с помощью Ctrl-C258    server.serve_forever()259```260261Альтернативный класс обработчика запросов, который использует потоки (объекты, подобные файлам, упрощающие взаимодействие за счет предоставления стандартного файлового интерфейса):262263```python264class MyTCPHandler(SocketServer.StreamRequestHandler):265266    def handle(self):267        # self.rfile – это файлоподобный объект, созданный обработчиком;268        # теперь можно использовать, например, readline() вместо прямых вызовов recv()269        self.data = self.rfile.readline().strip()270        print "{} wrote:".format(self.client_address[0])271        print self.data272        # Аналогично, self.wfile – это файлоподобный объект, используемый для записи ответа273        # клиенту274        self.wfile.write(self.data.upper())275```276277Разница в том, что вызов `readline()` во втором обработчике будет вызывать `recv()` несколько раз, пока не встретит символ новой строки, в то время как одиночный вызов `recv()` в первом обработчике просто вернет то, что было отправлено клиентом за один вызов `sendall()`.278279Это клиентская сторона:280281```python282import socket283import sys284285HOST, PORT = "localhost", 9999286data = " ".join(sys.argv[1:])287288# Создать сокет (SOCK_STREAM означает TCP-сокет)289sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)290291try:292    # Подключиться к серверу и отправить данные293    sock.connect((HOST, PORT))294    sock.sendall(data + "\n")295296    # Получить данные от сервера и завершить работу297    received = sock.recv(1024)298finally:299    sock.close()300301print "Sent:     {}".format(data)302print "Received: {}".format(received)303```304305Результат работы примера должен выглядеть примерно так:306307Сервер:308309```console310$ python TCPServer.py311127.0.0.1 wrote:312hello world with TCP313127.0.0.1 wrote:314python is nice315```316317Клиент:318319```console320$ python TCPClient.py hello world with TCP321Sent:     hello world with TCP322Received: HELLO WORLD WITH TCP323$ python TCPClient.py python is nice324Sent:     python is nice325Received: PYTHON IS NICE326```327328### 20.17.4.2. [`SocketServer.UDPServer`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.UDPServer) Пример329330Это серверная сторона:331332```python333import SocketServer334335class MyUDPHandler(SocketServer.BaseRequestHandler):336    """337    Этот класс работает аналогично классу-обработчику TCP, за исключением того, что338    self.request состоит из пары данных и клиентского сокета, и поскольку339    соединение отсутствует, адрес клиента должен быть указан явно340    при отправке данных обратно через sendto().341    """342343    def handle(self):344        data = self.request[0].strip()345        socket = self.request[1]346        print "{} wrote:".format(self.client_address[0])347        print data348        socket.sendto(data.upper(), self.client_address)349350if __name__ == "__main__":351    HOST, PORT = "localhost", 9999352    server = SocketServer.UDPServer((HOST, PORT), MyUDPHandler)353    server.serve_forever()354```355356Это клиентская сторона:357358```python359import socket360import sys361362HOST, PORT = "localhost", 9999363data = " ".join(sys.argv[1:])364365# SOCK_DGRAM – это тип сокета для UDP-сокетов366sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)367368# Как можно видеть, вызов connect() отсутствует; в UDP нет соединений.369# Вместо этого данные отправляются напрямую получателю через sendto().370sock.sendto(data + "\n", (HOST, PORT))371received = sock.recv(1024)372373print "Sent:     {}".format(data)374print "Received: {}".format(received)375```376377Результат работы примера должен выглядеть точно так же, как для примера TCP-сервера.378379### 20.17.4.3. Асинхронные примеси380381Для построения асинхронных обработчиков используйте классы [`ThreadingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ThreadingMixIn) и [`ForkingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ForkingMixIn).382383Пример для класса [`ThreadingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ThreadingMixIn):384385```python386import socket387import threading388import SocketServer389390class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):391392    def handle(self):393        data = self.request.recv(1024)394        cur_thread = threading.current_thread()395        response = "{}: {}".format(cur_thread.name, data)396        self.request.sendall(response)397398class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):399    pass400401def client(ip, port, message):402    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)403    sock.connect((ip, port))404    try:405        sock.sendall(message)406        response = sock.recv(1024)407        print "Received: {}".format(response)408    finally:409        sock.close()410411if __name__ == "__main__":412    # Порт 0 означает выбор произвольного неиспользуемого порта413    HOST, PORT = "localhost", 0414415    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)416    ip, port = server.server_address417418    # Запустить поток для сервера – этот поток затем запустит один419    # дополнительный поток на каждый запрос420    server_thread = threading.Thread(target=server.serve_forever)421    # Завершить поток сервера при завершении главного потока422    server_thread.daemon = True423    server_thread.start()424    print "Server loop running in thread:", server_thread.name425426    client(ip, port, "Hello World 1")427    client(ip, port, "Hello World 2")428    client(ip, port, "Hello World 3")429430    server.shutdown()431    server.server_close()432```433434Результат работы примера должен выглядеть примерно так:435436```console437$ python ThreadedTCPServer.py438Server loop running in thread: Thread-1439Received: Thread-2: Hello World 1440Received: Thread-3: Hello World 2441Received: Thread-4: Hello World 3442```443444Класс [`ForkingMixIn`](https://python-all.ru/2.7/library/socketserver.html#SocketServer.ForkingMixIn) используется аналогично, за исключением того, что сервер будет создавать новый процесс для каждого запроса. Доступен только на платформах POSIX, поддерживающих [`fork()`](https://python-all.ru/2.7/library/os.html#os.fork).445