socketserver.md
1> **Источник:** https://python-all.ru/3.15/library/socketserver.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# `socketserver` – фреймворк для сетевых серверов89**Исходный код:** [Lib/socketserver.py](https://python-all.ru/src/3.15/Lib/socketserver.py)1011---1213Модуль `socketserver` упрощает создание сетевых серверов.1415[Доступность](https://python-all.ru/3.15/library/intro.html#availability): не WASI.1617Этот модуль не работает или недоступен на WebAssembly. Подробнее см. [платформы WebAssembly](https://python-all.ru/3.15/library/intro.html#wasm-availability).1819Существует четыре базовых конкретных класса серверов:2021#### `class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)`2223Этот класс использует сетевой протокол TCP, который обеспечивает непрерывные потоки данных между клиентом и сервером. Если *bind\_and\_activate* равен true, конструктор автоматически пытается вызвать [`server_bind()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.server_bind) и [`server_activate()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.server_activate). Остальные параметры передаются базовому классу [`BaseServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer).2425Изменено в версии 3.15: Размер очереди по умолчанию теперь равен `socket.SOMAXCONN` для `socketserver.TCPServer`.2627#### `class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)`2829Использует дейтаграммы – отдельные пакеты информации, которые могут приходить не по порядку или теряться при передаче. Параметры те же, что и у [`TCPServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.TCPServer).3031#### `class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)`3233#### `class socketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)`3435Эти реже используемые классы похожи на классы TCP и UDP, но используют сокеты домена Unix; они недоступны на платформах, отличных от Unix. Параметры те же, что и у [`TCPServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.TCPServer).3637Эти четыре класса обрабатывают запросы *синхронно*: каждый запрос должен быть завершён до того, как начнётся следующий. Это не подходит, если каждый запрос требует много времени на выполнение из-за вычислительной сложности или большого объёма возвращаемых данных, которые клиент обрабатывает медленно. Решение – создавать отдельный процесс или поток для обработки каждого запроса; классы-примеси [`ForkingMixIn`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ForkingMixIn) и [`ThreadingMixIn`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ThreadingMixIn) позволяют реализовать асинхронное поведение.3839Создание сервера состоит из нескольких этапов. Сначала необходимо создать класс-обработчик запросов, унаследовав его от [`BaseRequestHandler`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler) и переопределив метод [`handle()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.handle); этот метод будет обрабатывать входящие запросы. Затем нужно создать экземпляр одного из классов сервера, передав ему адрес сервера и класс-обработчик. Рекомендуется использовать сервер в операторе [`with`](https://python-all.ru/3.15/reference/compound_stmts.html#with). После этого вызовите метод [`handle_request()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.handle_request) или [`serve_forever()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.serve_forever) объекта сервера для обработки одного или нескольких запросов. Наконец, вызовите [`server_close()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.server_close) для закрытия сокета (если только не использовался оператор `with`).4041При наследовании от [`ThreadingMixIn`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ThreadingMixIn) для поддержки многопоточности следует явно указать, как потоки должны вести себя при резком завершении работы. Класс `ThreadingMixIn` определяет атрибут *daemon\_threads*, который указывает, должен ли сервер ожидать завершения потоков. Установите этот флаг явно, если хотите, чтобы потоки работали автономно; значение по умолчанию – [`False`](https://python-all.ru/3.15/library/constants.html#False), то есть Python не завершится, пока все потоки, созданные `ThreadingMixIn`, не завершатся.4243Классы серверов имеют одни и те же внешние методы и атрибуты, независимо от того, какой сетевой протокол они используют.4445## Замечания по созданию серверов4647В иерархии наследования пять классов, четыре из которых представляют синхронные серверы четырёх типов:4849```python50+------------+51| BaseServer |52+------------+53 |54 v55+-----------+ +------------------+56| TCPServer |------->| UnixStreamServer |57+-----------+ +------------------+58 |59 v60+-----------+ +--------------------+61| UDPServer |------->| UnixDatagramServer |62+-----------+ +--------------------+63```6465Обратите внимание, что [`UnixDatagramServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.UnixDatagramServer) наследуется от [`UDPServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.UDPServer), а не от [`UnixStreamServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.UnixStreamServer) – единственное различие между IP-сервером и сервером Unix заключается в семействе адресов.6667#### `class socketserver.ForkingMixIn`6869#### `class socketserver.ThreadingMixIn`7071Версии с порождением процессов и потоками для каждого типа сервера можно создать с помощью этих классов-примесей. Например, [`ThreadingUDPServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ThreadingUDPServer) создаётся следующим образом:7273```python74class ThreadingUDPServer(ThreadingMixIn, UDPServer):75 pass76```7778Класс-примесь указывается первым, поскольку он переопределяет метод, определённый в [`UDPServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.UDPServer). Установка различных атрибутов также изменяет поведение базового механизма сервера.7980`ForkingMixIn` и классы Forking, упомянутые ниже, доступны только на POSIX-платформах, поддерживающих [`fork()`](https://python-all.ru/3.15/library/os.html#os.fork).8182#### `block_on_close`8384[`ForkingMixIn.server_close`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.server_close) ожидает завершения всех дочерних процессов, за исключением случая, когда атрибут [`block_on_close`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ThreadingMixIn.block_on_close) равен `False`.8586[`ThreadingMixIn.server_close`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.server_close) ожидает завершения всех не-демонических потоков, за исключением случая, когда атрибут [`block_on_close`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ThreadingMixIn.block_on_close) равен `False`.8788#### `max_children`8990Задаёт максимальное количество дочерних процессов, одновременно обрабатывающих запросы для `ForkingMixIn`. Если лимит достигнут, новые запросы ожидают завершения одного из дочерних процессов.9192#### `daemon_threads`9394Для `ThreadingMixIn` используются демонические потоки, если установить [`ThreadingMixIn.daemon_threads`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ThreadingMixIn.daemon_threads) в `True` – чтобы не ожидать завершения потоков.9596Изменено в версии 3.7: [`ForkingMixIn.server_close`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.server_close) и `ThreadingMixIn.server_close` теперь ожидают завершения всех дочерних процессов и не-демонических потоков. Добавлен новый атрибут класса [`ForkingMixIn.block_on_close`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ThreadingMixIn.block_on_close) для сохранения поведения, предшествующего версии 3.7.9798#### `class socketserver.ForkingTCPServer`99100#### `class socketserver.ForkingUDPServer`101102#### `class socketserver.ThreadingTCPServer`103104#### `class socketserver.ThreadingUDPServer`105106#### `class socketserver.ForkingUnixStreamServer`107108#### `class socketserver.ForkingUnixDatagramServer`109110#### `class socketserver.ThreadingUnixStreamServer`111112#### `class socketserver.ThreadingUnixDatagramServer`113114Эти классы предварительно определены с использованием примесных классов.115116Добавлено в версии 3.12: Классы `ForkingUnixStreamServer` и `ForkingUnixDatagramServer` были добавлены.117118Чтобы реализовать службу, необходимо создать класс, наследующий от [`BaseRequestHandler`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler), и переопределить его метод [`handle()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.handle). Затем можно запускать различные версии службы, комбинируя один из классов сервера с классом обработчика запросов. Класс обработчика запросов должен различаться для служб датаграмм и потоков. Эту сложность можно скрыть, используя подклассы обработчиков [`StreamRequestHandler`](https://python-all.ru/3.15/library/socketserver.html#socketserver.StreamRequestHandler) или [`DatagramRequestHandler`](https://python-all.ru/3.15/library/socketserver.html#socketserver.DatagramRequestHandler).119120Конечно, нужно подходить с умом. Например, нет смысла использовать сервер с порождением процессов (forking), если служба хранит состояние в памяти, которое может изменяться разными запросами, потому что изменения в дочернем процессе никогда не попадут в исходное состояние, хранящееся в родительском процессе и передаваемое каждому дочернему. В этом случае можно использовать потоковый сервер (threading), но, скорее всего, придётся использовать блокировки для защиты целостности общих данных.121122С другой стороны, если создаётся HTTP-сервер, где все данные хранятся внешне (например, в файловой системе), синхронный класс фактически сделает службу «глухой» на время обработки одного запроса – что может занять очень много времени, если клиент медленно получает все запрошенные данные. Здесь подойдёт потоковый сервер или сервер с порождением процессов.123124В некоторых случаях может быть уместно обработать часть запроса синхронно, но завершить обработку в порождённом дочернем процессе в зависимости от данных запроса. Этого можно добиться, используя синхронный сервер и выполняя явный fork (порождение процесса) в методе [`handle()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.handle) класса обработчика запросов.125126Другой подход к обработке нескольких одновременных запросов в среде, не поддерживающей ни потоки, ни [`fork()`](https://python-all.ru/3.15/library/os.html#os.fork) (или если они слишком дороги или неподходящи для службы) – поддерживать явную таблицу частично выполненных запросов и использовать [`selectors`](https://python-all.ru/3.15/library/selectors.html#module-selectors) для определения, какой запрос обрабатывать следующим (или нужно ли обрабатывать новый входящий запрос). Это особенно важно для потоковых служб, где каждый клиент может потенциально оставаться подключённым долгое время (если потоки или подпроцессы не могут использоваться).127128## Объекты сервера129130#### `class socketserver.BaseServer(server_address, RequestHandlerClass)`131132Это суперкласс для всех объектов Server в модуле. Он определяет интерфейс, приведенный ниже, но не реализует большинство методов – это делается в подклассах. Два параметра хранятся в соответствующих атрибутах [`server_address`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.server_address) и [`RequestHandlerClass`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.RequestHandlerClass).133134#### `fileno()`135136Возвращает целочисленный файловый дескриптор сокета, на котором сервер прослушивает соединения. Эта функция чаще всего передается в [`selectors`](https://python-all.ru/3.15/library/selectors.html#module-selectors), чтобы обеспечить мониторинг нескольких серверов в одном процессе.137138#### `handle_request()`139140Обрабатывает один запрос. Эта функция вызывает следующие методы по порядку: [`get_request()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.get_request), [`verify_request()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.verify_request) и [`process_request()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.process_request). Если предоставленный пользователем метод [`handle()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.handle) класса-обработчика вызывает исключение, вызывается метод [`handle_error()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.handle_error) сервера. Если в течение [`timeout`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.timeout) секунд не поступило ни одного запроса, будет вызван [`handle_timeout()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.handle_timeout), и `handle_request()` завершится.141142#### `serve_forever(poll_interval=0.5)`143144Обрабатывает запросы до явного запроса [`shutdown()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.shutdown). Опрашивает завершение каждые *poll\_interval* секунд. Игнорирует атрибут [`timeout`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.timeout). Также вызывает [`service_actions()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.service_actions), который может использоваться подклассом или миксином для предоставления действий, специфичных для данной службы. Например, класс [`ForkingMixIn`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ForkingMixIn) использует `service_actions()` для очистки процессов-зомби.145146Изменено в версии 3.3: Добавлен вызов `service_actions` в метод `serve_forever`.147148#### `service_actions()`149150Вызывается в цикле [`serve_forever()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.serve_forever). Этот метод может быть переопределен подклассами или классами-миксинами для выполнения действий, специфичных для данной службы, например, действий по очистке.151152Добавлено в версии 3.3.153154#### `shutdown()`155156Сообщает циклу [`serve_forever()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.serve_forever) остановиться и ждет завершения. `shutdown()` должен вызываться, пока `serve_forever()` выполняется в другом потоке, иначе возникнет взаимоблокировка.157158#### `server_close()`159160Выполняет очистку сервера. Может быть переопределен.161162#### `address_family`163164Семейство протоколов, к которому принадлежит сокет сервера. Типичные примеры: [`socket.AF_INET`](https://python-all.ru/3.15/library/socket.html#socket.AF_INET), [`socket.AF_INET6`](https://python-all.ru/3.15/library/socket.html#socket.AF_INET6) и [`socket.AF_UNIX`](https://python-all.ru/3.15/library/socket.html#socket.AF_UNIX). Наследуйте классы TCP- или UDP-сервера из этого модуля, установив атрибут класса `address_family = AF_INET6`, если нужны классы сервера для IPv6.165166#### `RequestHandlerClass`167168Класс обработчика запросов, предоставленный пользователем; экземпляр этого класса создаётся для каждого запроса.169170#### `server_address`171172Адрес, на котором сервер принимает соединения. Формат адресов зависит от семейства протоколов; подробнее см. документацию модуля [`socket`](https://python-all.ru/3.15/library/socket.html#module-socket). Для интернет-протоколов это кортеж, содержащий строку с адресом и целочисленный номер порта: например, `('127.0.0.1', 80)`.173174#### `socket`175176Объект сокета, через который сервер будет принимать входящие запросы.177178Классы серверов поддерживают следующие переменные класса:179180#### `allow_reuse_address`181182Определяет, разрешает ли сервер повторное использование адреса. По умолчанию [`False`](https://python-all.ru/3.15/library/constants.html#False); значение можно изменить в подклассах, чтобы задать другую политику.183184#### `request_queue_size`185186Размер очереди запросов. Если обработка одного запроса занимает много времени, запросы, поступающие, пока сервер занят, помещаются в очередь – до [`request_queue_size`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.request_queue_size) запросов. Когда очередь заполняется, дальнейшие запросы от клиентов получают ошибку «Connection denied». Обычно значение по умолчанию – 5, но его можно переопределить в подклассах.187188#### `socket_type`189190Тип сокета, используемый сервером; распространённые значения: [`socket.SOCK_STREAM`](https://python-all.ru/3.15/library/socket.html#socket.SOCK_STREAM) и [`socket.SOCK_DGRAM`](https://python-all.ru/3.15/library/socket.html#socket.SOCK_DGRAM).191192#### `timeout`193194Длительность тайм-аута в секундах или [`None`](https://python-all.ru/3.15/library/constants.html#None), если тайм-аут не нужен. Если [`handle_request()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.handle_request) не получает входящих запросов в течение периода тайм-аута, вызывается метод [`handle_timeout()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.handle_timeout).195196Существуют различные методы сервера, которые можно переопределить в подклассах базовых классов серверов, например [`TCPServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.TCPServer); эти методы не предназначены для внешних пользователей объекта сервера.197198#### `finish_request(request, client_address)`199200Непосредственно обрабатывает запрос, создавая экземпляр [`RequestHandlerClass`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.RequestHandlerClass) и вызывая его метод [`handle()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.handle).201202#### `get_request()`203204Должен принять запрос из сокета и вернуть кортеж из двух элементов, содержащий *новый* объект сокета для взаимодействия с клиентом и адрес клиента.205206#### `handle_error(request, client_address)`207208Эта функция вызывается, если метод [`handle()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.handle) экземпляра [`RequestHandlerClass`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.RequestHandlerClass) возбуждает исключение. По умолчанию трассировка выводится в стандартный поток ошибок, после чего обработка следующих запросов продолжается.209210Изменено в версии 3.6: Теперь вызывается только для исключений, производных от класса [`Exception`](https://python-all.ru/3.15/library/exceptions.html#Exception).211212#### `handle_timeout()`213214Эта функция вызывается, когда атрибут [`timeout`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.timeout) установлен в значение, отличное от [`None`](https://python-all.ru/3.15/library/constants.html#None), и период тайм-аута истёк без получения запросов. По умолчанию для серверов с порождением процессов (forking) собирается статус завершившихся дочерних процессов; в многопоточных серверах этот метод ничего не делает.215216#### `process_request(request, client_address)`217218Вызывает [`finish_request()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.finish_request) для создания экземпляра [`RequestHandlerClass`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.RequestHandlerClass). При необходимости эта функция может создать новый процесс или поток для обработки запроса; так поступают классы [`ForkingMixIn`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ForkingMixIn) и [`ThreadingMixIn`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ThreadingMixIn).219220#### `server_activate()`221222Вызывается конструктором сервера для активации сервера. По умолчанию для TCP-сервера просто вызывает [`listen()`](https://python-all.ru/3.15/library/socket.html#socket.socket.listen) на сокете сервера. Можно переопределить.223224#### `server_bind()`225226Вызывается конструктором сервера для привязки сокета к нужному адресу. Можно переопределить.227228#### `verify_request(request, client_address)`229230Должна возвращать логическое значение; если значение равно [`True`](https://python-all.ru/3.15/library/constants.html#True), запрос будет обработан, а если [`False`](https://python-all.ru/3.15/library/constants.html#False), запрос будет отклонен. Эта функция может быть переопределена для реализации контроля доступа к серверу. Реализация по умолчанию всегда возвращает `True`.231232Изменено в версии 3.6: Добавлена поддержка протокола [контекстного менеджера](https://python-all.ru/3.15/glossary.html#term-context-manager). Выход из контекстного менеджера эквивалентен вызову [`server_close()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.server_close).233234## Объекты обработчика запросов235236#### `class socketserver.BaseRequestHandler`237238Это суперкласс всех объектов-обработчиков запросов. Он определяет интерфейс, приведенный ниже. Конкретный подкласс обработчика запросов должен определить новый метод [`handle()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.handle) и может переопределять любые другие методы. Новый экземпляр подкласса создается для каждого запроса.239240#### `setup()`241242Вызывается перед методом [`handle()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.handle) для выполнения необходимых действий по инициализации. Реализация по умолчанию ничего не делает.243244#### `handle()`245246Эта функция должна выполнять всю работу, необходимую для обслуживания запроса. Реализация по умолчанию ничего не делает. Ей доступны несколько атрибутов экземпляра: запрос доступен как [`request`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.request); адрес клиента как [`client_address`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.client_address); а экземпляр сервера как [`server`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.server), на случай, если потребуется доступ к информации, специфичной для сервера.247248Тип [`request`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.request) различается для служб дейтаграмм и потоков. Для потоковых служб `request` – это объект сокета; для служб дейтаграмм `request` – это пара из строки и сокета.249250#### `finish()`251252Вызывается после метода [`handle()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.handle) для выполнения необходимых действий по очистке. Реализация по умолчанию ничего не делает. Если [`setup()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.setup) вызывает исключение, эта функция не будет вызвана.253254#### `request`255256*Новый* объект [`socket.socket`](https://python-all.ru/3.15/library/socket.html#socket.socket), используемый для взаимодействия с клиентом.257258#### `client_address`259260Адрес клиента, возвращаемый [`BaseServer.get_request()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer.get_request).261262#### `server`263264Объект [`BaseServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseServer), используемый для обработки запроса.265266#### `class socketserver.StreamRequestHandler`267268#### `class socketserver.DatagramRequestHandler`269270Эти подклассы [`BaseRequestHandler`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler) переопределяют методы [`setup()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.setup) и [`finish()`](https://python-all.ru/3.15/library/socketserver.html#socketserver.BaseRequestHandler.finish) и предоставляют атрибуты [`rfile`](https://python-all.ru/3.15/library/socketserver.html#socketserver.DatagramRequestHandler.rfile) и [`wfile`](https://python-all.ru/3.15/library/socketserver.html#socketserver.DatagramRequestHandler.wfile).271272#### `rfile`273274Файловый объект, из которого считывается запрос. Поддерживает интерфейс [`io.BufferedIOBase`](https://python-all.ru/3.15/library/io.html#io.BufferedIOBase) readable.275276#### `wfile`277278Файловый объект, в который записывается ответ. Поддерживает интерфейс [`io.BufferedIOBase`](https://python-all.ru/3.15/library/io.html#io.BufferedIOBase) writable.279280Изменено в версии 3.6: [`wfile`](https://python-all.ru/3.15/library/socketserver.html#socketserver.DatagramRequestHandler.wfile) также поддерживает интерфейс [`io.BufferedIOBase`](https://python-all.ru/3.15/library/io.html#io.BufferedIOBase) writable.281282## Примеры283284### [`socketserver.TCPServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.TCPServer) Пример285286Это серверная сторона:287288```python289import socketserver290291class MyTCPHandler(socketserver.BaseRequestHandler):292 """293 Класс обработчика запросов для нашего сервера.294295 Он создаётся один раз на каждое подключение к серверу и должен296 переопределять метод handle() для реализации взаимодействия с297 клиентом.298 """299300 def handle(self):301 # self.request – это TCP-сокет, подключённый к клиенту302 pieces = [b'']303 total = 0304 while b'\n' not in pieces[-1] and total < 10_000:305 pieces.append(self.request.recv(2000))306 total += len(pieces[-1])307 self.data = b''.join(pieces)308 print(f"Received from {self.client_address[0]}:")309 print(self.data.decode("utf-8"))310 # просто отправляет обратно те же данные, но в верхнем регистре311 self.request.sendall(self.data.upper())312 # после возврата сокет будет закрыт.313314if __name__ == "__main__":315 HOST, PORT = "localhost", 9999316317 # Создаём сервер, привязываясь к localhost на порту 9999318 with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:319 # Запускаем сервер; он будет работать, пока вы320 # не прервёте программу с помощью Ctrl-C321 server.serve_forever()322```323324Альтернативный класс обработчика запросов, который использует потоки (объекты, подобные файлам, упрощающие взаимодействие за счет предоставления стандартного файлового интерфейса):325326```python327class MyTCPHandler(socketserver.StreamRequestHandler):328329 def handle(self):330 # self.rfile – это файлоподобный объект, созданный обработчиком.331 # Теперь можно использовать, например, readline() вместо прямых вызовов recv().332 # Мы ограничиваемся 10 000 байт, чтобы избежать злоупотреблений со стороны отправителя.333 self.data = self.rfile.readline(10000).rstrip()334 print(f"{self.client_address[0]} wrote:")335 print(self.data.decode("utf-8"))336 # Аналогично, self.wfile – это файлоподобный объект, используемый для записи ответа337 # клиенту338 self.wfile.write(self.data.upper())339```340341Разница в том, что вызов `readline()` во втором обработчике вызывает `recv()` несколько раз, пока не встретит символ новой строки, тогда как первый обработчик должен был использовать цикл `recv()` для накопления данных до символа новой строки. Если бы он использовал один `recv()` без цикла, он бы просто вернул то, что было получено от клиента на данный момент. TCP основан на потоках: данные поступают в том порядке, в котором были отправлены, но нет корреляции между вызовами клиента `send()` или `sendall()` и количеством вызовов `recv()` на сервере, необходимых для их получения.342343Это клиентская сторона:344345```python346import socket347import sys348349HOST, PORT = "localhost", 9999350data = " ".join(sys.argv[1:])351352# Создать сокет (SOCK_STREAM означает TCP-сокет)353with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:354 # Подключиться к серверу и отправить данные355 sock.connect((HOST, PORT))356 sock.sendall(bytes(data, "utf-8"))357 sock.sendall(b"\n")358359 # Получить данные от сервера и завершить работу360 received = str(sock.recv(1024), "utf-8")361362print("Sent: ", data)363print("Received:", received)364```365366Результат работы примера должен выглядеть примерно так:367368Сервер:369370```console371$ python TCPServer.py372127.0.0.1 wrote:373b'hello world with TCP'374127.0.0.1 wrote:375b'python is nice'376```377378Клиент:379380```console381$ python TCPClient.py hello world with TCP382Sent: hello world with TCP383Received: HELLO WORLD WITH TCP384$ python TCPClient.py python is nice385Sent: python is nice386Received: PYTHON IS NICE387```388389### [`socketserver.UDPServer`](https://python-all.ru/3.15/library/socketserver.html#socketserver.UDPServer) Пример390391Это серверная сторона:392393```python394import socketserver395396class MyUDPHandler(socketserver.BaseRequestHandler):397 """398 Этот класс работает аналогично классу-обработчику TCP, за исключением того, что399 self.request состоит из пары данных и клиентского сокета, и поскольку400 соединение отсутствует, адрес клиента должен быть указан явно401 при отправке данных обратно через sendto().402 """403404 def handle(self):405 data = self.request[0].strip()406 socket = self.request[1]407 print(f"{self.client_address[0]} wrote:")408 print(data)409 socket.sendto(data.upper(), self.client_address)410411if __name__ == "__main__":412 HOST, PORT = "localhost", 9999413 with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server:414 server.serve_forever()415```416417Это клиентская сторона:418419```python420import socket421import sys422423HOST, PORT = "localhost", 9999424data = " ".join(sys.argv[1:])425426# SOCK_DGRAM – это тип сокета для UDP-сокетов427sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)428429# Как можно видеть, вызов connect() отсутствует; в UDP нет соединений.430# Вместо этого данные отправляются напрямую получателю через sendto().431sock.sendto(bytes(data + "\n", "utf-8"), (HOST, PORT))432received = str(sock.recv(1024), "utf-8")433434print("Sent: ", data)435print("Received:", received)436```437438Результат работы примера должен выглядеть точно так же, как для примера TCP-сервера.439440### Асинхронные Mixins441442Для построения асинхронных обработчиков используйте классы [`ThreadingMixIn`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ThreadingMixIn) и [`ForkingMixIn`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ForkingMixIn).443444Пример для класса [`ThreadingMixIn`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ThreadingMixIn):445446```python447import socket448import threading449import socketserver450451class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):452453 def handle(self):454 data = str(self.request.recv(1024), 'ascii')455 cur_thread = threading.current_thread()456 response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')457 self.request.sendall(response)458459class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):460 pass461462def client(ip, port, message):463 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:464 sock.connect((ip, port))465 sock.sendall(bytes(message, 'ascii'))466 response = str(sock.recv(1024), 'ascii')467 print("Received: {}".format(response))468469if __name__ == "__main__":470 # Порт 0 означает выбор произвольного неиспользуемого порта471 HOST, PORT = "localhost", 0472473 server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)474 with server:475 ip, port = server.server_address476477 # Запустить поток для сервера – этот поток затем запустит один478 # дополнительный поток на каждый запрос479 server_thread = threading.Thread(target=server.serve_forever)480 # Завершить поток сервера при завершении главного потока481 server_thread.daemon = True482 server_thread.start()483 print("Server loop running in thread:", server_thread.name)484485 client(ip, port, "Hello World 1")486 client(ip, port, "Hello World 2")487 client(ip, port, "Hello World 3")488489 server.shutdown()490```491492Результат работы примера должен выглядеть примерно так:493494```console495$ python ThreadedTCPServer.py496Server loop running in thread: Thread-1497Received: Thread-2: Hello World 1498Received: Thread-3: Hello World 2499Received: Thread-4: Hello World 3500```501502Класс [`ForkingMixIn`](https://python-all.ru/3.15/library/socketserver.html#socketserver.ForkingMixIn) используется аналогично, за исключением того, что сервер будет создавать новый процесс для каждого запроса. Доступен только на платформах POSIX, поддерживающих [`fork()`](https://python-all.ru/3.15/library/os.html#os.fork).503