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

asyncore.md

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

1> **Источник:** https://python-all.ru/3.11/library/asyncore.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# [`asyncore`](https://python-all.ru/3.11/library/asyncore.html#module-asyncore) – Асинхронный обработчик сокетов89**Исходный код:** [Lib/asyncore.py](https://python-all.ru/src/3.11/Lib/asyncore.py)1011Устарело с версии 3.6, будет удалено в версии 3.12: Модуль [`asyncore`](https://python-all.ru/3.11/library/asyncore.html#module-asyncore) устарел (см. [**PEP 594**](https://python-all.ru/3.11/library/asyncore.html) подробнее). Вместо него используйте [`asyncio`](https://python-all.ru/3.11/library/asyncio.html#module-asyncio).1213---1415> **Примечание**16>17> Этот модуль существует только для обратной совместимости. Для нового кода рекомендуется использовать [`asyncio`](https://python-all.ru/3.11/library/asyncio.html#module-asyncio).1819Этот модуль предоставляет базовую инфраструктуру для написания клиентов и серверов асинхронных сокетных служб.2021[Доступность](https://python-all.ru/3.11/library/intro.html#availability): not Emscripten, not WASI.2223Этот модуль не работает или недоступен на платформах WebAssembly `wasm32-emscripten` и `wasm32-wasi`. См. [платформы WebAssembly](https://python-all.ru/3.11/library/intro.html#wasm-availability) для получения дополнительной информации.2425Есть только два способа заставить программу на одном процессоре делать «более одного дела одновременно». Многопоточное программирование – самый простой и популярный способ, но есть и другой, совершенно иной метод, который даёт почти все преимущества многопоточности без использования нескольких потоков. Он действительно практичен только в том случае, если программа в основном связана с вводом-выводом. Если программа загружает процессор, то, вероятно, на самом деле требуются вытесняющие потоки с планированием. Однако сетевые серверы редко бывают привязаны к процессору.2627Если ваша операционная система поддерживает системный вызов `select()` в своей библиотеке ввода-вывода (а поддерживают почти все), то вы можете использовать его для одновременной работы с несколькими каналами связи, выполняя другую работу, пока ваш ввод-вывод происходит в «фоне». Хотя эта стратегия может показаться странной и сложной, особенно поначалу, во многих отношениях она проще для понимания и управления, чем многопоточное программирование. Модуль [`asyncore`](https://python-all.ru/3.11/library/asyncore.html#module-asyncore) решает за вас многие сложные проблемы, делая создание сложных высокопроизводительных сетевых серверов и клиентов очень простым. Для «диалоговых» приложений и протоколов незаменим сопутствующий модуль [`asynchat`](https://python-all.ru/3.11/library/asynchat.html#module-asynchat).2829Основная идея обоих модулей – создать один или несколько сетевых *каналов*, экземпляров классов [`asyncore.dispatcher`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher) и [`asynchat.async_chat`](https://python-all.ru/3.11/library/asynchat.html#asynchat.async_chat). Создание каналов добавляет их в глобальную карту, используемую функцией [`loop()`](https://python-all.ru/3.11/library/asyncore.html#asyncore.loop), если вы не предоставите ей собственную *карту*.3031Как только начальный канал (или каналы) созданы, вызов функции [`loop()`](https://python-all.ru/3.11/library/asyncore.html#asyncore.loop) активирует обслуживание каналов, которое продолжается до тех пор, пока последний канал (включая те, что были добавлены в карту во время асинхронного обслуживания) не будет закрыт.3233#### `asyncore.loop([timeout[, use_poll[, map[, count]]]])`3435Входит в цикл опроса, который завершается после count проходов или когда все открытые каналы будут закрыты. Все аргументы необязательны. Параметр *count* по умолчанию равен `None`, в результате чего цикл завершается только после закрытия всех каналов. Аргумент *timeout* задаёт параметр тайм-аута для соответствующего вызова [`select()`](https://python-all.ru/3.11/library/select.html#select.select) или [`poll()`](https://python-all.ru/3.11/library/select.html#select.poll), измеряемый в секундах; по умолчанию 30 секунд. Параметр *use\_poll*, если равен true, указывает, что [`poll()`](https://python-all.ru/3.11/library/select.html#select.poll) должен использоваться предпочтительнее, чем [`select()`](https://python-all.ru/3.11/library/select.html#select.select) (по умолчанию `False`).3637Параметр *map* – это словарь, элементами которого являются отслеживаемые каналы. При закрытии каналов они удаляются из своей карты. Если *map* опущен, используется глобальная карта. Каналы (экземпляры [`asyncore.dispatcher`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher), [`asynchat.async_chat`](https://python-all.ru/3.11/library/asynchat.html#asynchat.async_chat) и их подклассов) могут свободно смешиваться в карте.3839#### `class asyncore.dispatcher`4041Класс [`dispatcher`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher) представляет собой тонкую обёртку вокруг низкоуровневого сокетного объекта. Чтобы сделать его более полезным, у него есть несколько методов обработки событий, которые вызываются из асинхронного цикла. В остальном его можно рассматривать как обычный неблокирующий сокетный объект.4243Возникновение низкоуровневых событий в определённые моменты или в определённых состояниях соединения сообщает асинхронному циклу, что произошли некоторые высокоуровневые события. Например, если мы запросили подключение сокета к другому хосту, мы знаем, что соединение установлено, когда сокет впервые становится доступным для записи (в этот момент можно писать в него, рассчитывая на успех). Подразумеваемые высокоуровневые события:4445| Событие | Описание |46| --- | --- |47| `handle_connect()` | Подразумевается первым событием чтения или записи |48| `handle_close()` | Подразумевается событием чтения, когда данные недоступны |49| `handle_accepted()` | Подразумевается событием чтения на слушающем сокете |5051Во время асинхронной обработки методы [`readable()`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher.readable) и [`writable()`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher.writable) каждого сопоставленного канала используются для определения, должен ли сокет канала быть добавлен в список каналов, `select()`ed или `poll()`ed для событий чтения и записи.5253Таким образом, набор событий канала шире, чем базовые события сокета. Полный набор методов, которые можно переопределить в вашем подклассе, приведён ниже:5455#### `handle_read()`5657Вызывается, когда асинхронный цикл обнаруживает, что вызов `read()` на сокете канала будет успешным.5859#### `handle_write()`6061Вызывается, когда асинхронный цикл обнаруживает, что сокет, доступный для записи, можно записать. Часто этот метод реализует необходимую буферизацию для производительности. Например:6263```python64def handle_write(self):65    sent = self.send(self.buffer)66    self.buffer = self.buffer[sent:]67```6869#### `handle_expt()`7071Вызывается при наличии внеполосных данных (OOB) для сокетного соединения. Это почти никогда не происходит, так как OOB поддерживается слабо и редко используется.7273#### `handle_connect()`7475Вызывается, когда сокет активного инициатора действительно устанавливает соединение. Может, например, отправить приветственный баннер или инициировать согласование протокола с удалённой конечной точкой.7677#### `handle_close()`7879Вызывается при закрытии сокета.8081#### `handle_error()`8283Вызывается, когда возникает исключение, которое иначе не обрабатывается. Версия по умолчанию выводит сокращённую трассировку.8485#### `handle_accept()`8687Вызывается на слушающих каналах (пассивных инициаторах), когда может быть установлено соединение с новой удалённой конечной точкой, которая выполнила вызов [`connect()`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher.connect) для локальной конечной точки. Устарело в версии 3.2; вместо этого используйте [`handle_accepted()`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher.handle_accepted).8889Устарело с версии 3.2.9091#### `handle_accepted(sock, addr)`9293Вызывается на слушающих каналах (пассивных открывателях), когда установлено соединение с новым удалённым узлом, который отправил вызов [`connect()`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher.connect) для локального узла. *sock* – это *новый* объект сокета, пригодный для отправки и получения данных по соединению, а *addr* – адрес, привязанный к сокету на другом конце соединения.9495Новое в версии 3.2.9697#### `readable()`9899Вызывается на каждом витке асинхронного цикла, чтобы определить, следует ли добавить сокет канала в список, в котором могут происходить события чтения. Метод по умолчанию просто возвращает `True`, указывая, что по умолчанию все каналы будут заинтересованы в событиях чтения.100101#### `writable()`102103Вызывается на каждом витке асинхронного цикла, чтобы определить, следует ли добавить сокет канала в список, в котором могут происходить события записи. Метод по умолчанию просто возвращает `True`, указывая, что по умолчанию все каналы будут заинтересованы в событиях записи.104105Кроме того, каждый канал делегирует или расширяет многие методы сокета. Большинство из них почти идентичны своим сокетным аналогам.106107#### `create_socket(family=socket.AF_INET, type=socket.SOCK_STREAM)`108109Это идентично созданию обычного сокета и использует те же параметры создания. Обратитесь к документации [`socket`](https://python-all.ru/3.11/library/socket.html#module-socket) за информацией о создании сокетов.110111Изменено в версии 3.3: *family* и *type* аргументы могут быть опущены.112113#### `connect(address)`114115Как и для обычного объекта сокета, *address* – это кортеж, первый элемент которого – хост для подключения, а второй – номер порта.116117#### `send(data)`118119Отправляет *data* на удалённый узел сокета.120121#### `recv(buffer_size)`122123Читает не более *buffer\_size* байт с удалённого узла сокета. Пустой объект bytes означает, что канал был закрыт с другого конца.124125Обратите внимание, что [`recv()`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher.recv) может порождать [`BlockingIOError`](https://python-all.ru/3.11/library/exceptions.html#BlockingIOError), даже если [`select.select()`](https://python-all.ru/3.11/library/select.html#select.select) или [`select.poll()`](https://python-all.ru/3.11/library/select.html#select.poll) сообщили, что сокет готов к чтению.126127#### `listen(backlog)`128129Ожидает входящие соединения на сокете. Аргумент *backlog* задаёт максимальное количество соединений в очереди и должен быть не менее 1; максимальное значение зависит от системы (обычно 5).130131#### `bind(address)`132133Привязывает сокет к *address*. Сокет не должен быть уже привязан. (Формат *address* зависит от адресного семейства – обратитесь к документации [`socket`](https://python-all.ru/3.11/library/socket.html#module-socket) для получения дополнительной информации.) Чтобы пометить сокет как повторно используемый (установив параметр `SO_REUSEADDR`), вызовите метод `set_reuse_addr()` объекта [`dispatcher`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher).134135#### `accept()`136137Принимает соединение. Сокет должен быть привязан к адресу и ожидать соединения. Возвращаемое значение может быть либо `None`, либо парой `(conn, address)`, где *conn* – это *новый* объект сокета, пригодный для отправки и получения данных по соединению, а *address* – адрес, привязанный к сокету на другом конце соединения. Если возвращено `None`, это означает, что соединение не установлено; в этом случае сервер должен просто проигнорировать это событие и продолжать ожидать новые входящие соединения.138139#### `close()`140141Закрывает сокет. Все последующие операции с объектом сокета будут завершаться ошибкой. Удалённый узел больше не будет получать данные (после отправки данных из очереди). Сокеты автоматически закрываются при сборке мусора.142143#### `class asyncore.dispatcher_with_send`144145Подкласс [`dispatcher`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher), который добавляет простую возможность буферизованного вывода, полезен для простых клиентов. Для более сложных случаев используйте [`asynchat.async_chat`](https://python-all.ru/3.11/library/asynchat.html#asynchat.async_chat).146147#### `class asyncore.file_dispatcher`148149file\_dispatcher принимает файловый дескриптор или [файловый объект](https://python-all.ru/3.11/glossary.html#term-file-object) вместе с необязательным аргументом map и оборачивает его для использования с функциями `poll()` или `loop()`. Если передан файловый объект или что-либо с методом `fileno()`, этот метод будет вызван и передан конструктору [`file_wrapper`](https://python-all.ru/3.11/library/asyncore.html#asyncore.file_wrapper).150151[Доступность](https://python-all.ru/3.11/library/intro.html#availability): Unix.152153#### `class asyncore.file_wrapper`154155file\_wrapper принимает целочисленный файловый дескриптор и вызывает [`os.dup()`](https://python-all.ru/3.11/library/os.html#os.dup) для дублирования дескриптора, чтобы исходный дескриптор можно было закрыть независимо от file\_wrapper. Этот класс реализует достаточное количество методов для эмуляции сокета для использования классом [`file_dispatcher`](https://python-all.ru/3.11/library/asyncore.html#asyncore.file_dispatcher).156157[Доступность](https://python-all.ru/3.11/library/intro.html#availability): Unix.158159## asyncore Пример базового HTTP-клиента160161Вот очень простой HTTP-клиент, который использует класс [`dispatcher`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher) для реализации обработки сокетов:162163```python164import asyncore165166class HTTPClient(asyncore.dispatcher):167168    def __init__(self, host, path):169        asyncore.dispatcher.__init__(self)170        self.create_socket()171        self.connect( (host, 80) )172        self.buffer = bytes('GET %s HTTP/1.0\r\nHost: %s\r\n\r\n' %173                            (path, host), 'ascii')174175    def handle_connect(self):176        pass177178    def handle_close(self):179        self.close()180181    def handle_read(self):182        print(self.recv(8192))183184    def writable(self):185        return (len(self.buffer) > 0)186187    def handle_write(self):188        sent = self.send(self.buffer)189        self.buffer = self.buffer[sent:]190191client = HTTPClient('www.python.org', '/')192asyncore.loop()193```194195## asyncore Пример простого эхо-сервера196197Вот простой эхо-сервер, который использует класс [`dispatcher`](https://python-all.ru/3.11/library/asyncore.html#asyncore.dispatcher) для приёма соединений и направляет входящие соединения обработчику:198199```python200import asyncore201202class EchoHandler(asyncore.dispatcher_with_send):203204    def handle_read(self):205        data = self.recv(8192)206        if data:207            self.send(data)208209class EchoServer(asyncore.dispatcher):210211    def __init__(self, host, port):212        asyncore.dispatcher.__init__(self)213        self.create_socket()214        self.set_reuse_addr()215        self.bind((host, port))216        self.listen(5)217218    def handle_accepted(self, sock, addr):219        print('Incoming connection from %s' % repr(addr))220        handler = EchoHandler(sock)221222server = EchoServer('localhost', 8080)223asyncore.loop()224```225