> **Источник:** https://python-all.ru/3.0/library/asyncore.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# `asyncore` – Асинхронный обработчик сокетов

Этот модуль предоставляет базовую инфраструктуру для написания клиентов и серверов асинхронных сокетных служб.

Есть только два способа заставить программу на одном процессоре делать «более одного дела одновременно». Многопоточное программирование – самый простой и популярный способ, но есть и другой, совершенно иной метод, который даёт почти все преимущества многопоточности без использования нескольких потоков. Он действительно практичен только в том случае, если программа в основном связана с вводом-выводом. Если программа загружает процессор, то, вероятно, на самом деле требуются вытесняющие потоки с планированием. Однако сетевые серверы редко бывают привязаны к процессору.

Если ваша операционная система поддерживает системный вызов `select` в своей библиотеке ввода-вывода (а так делают почти все), вы можете использовать его для одновременной работы с несколькими каналами связи; выполняя другую работу, пока ваш ввод-вывод происходит в «фоне». Хотя такая стратегия может показаться странной и сложной, особенно поначалу, во многих отношениях она проще для понимания и управления, чем многопоточное программирование. Модуль `asyncore` решает многие сложные проблемы, превращая задачу построения сложных высокопроизводительных сетевых серверов и клиентов в простую задачу. Для «диалоговых» приложений и протоколов незаменим модуль-компаньон [`asynchat`](https://python-all.ru/3.0/library/asynchat.html#module-asynchat) модуль.

Основная идея обоих модулей – создать один или несколько сетевых *каналов*, экземпляров классов [`asyncore.dispatcher`](https://python-all.ru/3.0/library/asyncore.html#asyncore.dispatcher) и [`asynchat.async_chat`](https://python-all.ru/3.0/library/asynchat.html#asynchat.async_chat). Создание каналов добавляет их в глобальную карту, используемую функцией [`loop()`](https://python-all.ru/3.0/library/asyncore.html#asyncore.loop), если вы не предоставите ей собственную *карту*.

После создания начального канала (или каналов) вызов функции [`loop()`](https://python-all.ru/3.0/library/asyncore.html#asyncore.loop) активирует обслуживание каналов, которое продолжается до тех пор, пока последний канал (включая те, что были добавлены в карту во время асинхронного обслуживания) не будет закрыт.

#### `[asyncore.loop]asyncore.loop([timeout[, use_poll[, map[, count]]]])`

Enter a polling loop that terminates after count passes or all open channels have been closed. All arguments are optional. The *count* parameter defaults to None, resulting in the loop terminating only when all channels have been closed. The *timeout* argument sets the timeout parameter for the appropriate `select()` or `poll()` call, measured in seconds; the default is 30 seconds. The *use\_poll* parameter, if true, indicates that `poll()` should be used in preference to `select()` (the default is `False`).

The *map* parameter is a dictionary whose items are the channels to watch. As channels are closed they are deleted from their map. If *map* is omitted, a global map is used. Channels (instances of [`asyncore.dispatcher`](https://python-all.ru/3.0/library/asyncore.html#asyncore.dispatcher), [`asynchat.async_chat`](https://python-all.ru/3.0/library/asynchat.html#asynchat.async_chat) and subclasses thereof) can freely be mixed in the map.

#### `[asyncore.dispatcher]class asyncore.dispatcher`

Класс [`dispatcher`](https://python-all.ru/3.0/library/asyncore.html#asyncore.dispatcher) – это тонкая обёртка вокруг низкоуровневого сокетного объекта. Чтобы сделать его более полезным, у него есть несколько методов для обработки событий, которые вызываются из асинхронного цикла. В остальном его можно рассматривать как обычный неблокирующий сокетный объект.

Возникновение низкоуровневых событий в определённые моменты или в определённых состояниях соединения сообщает асинхронному циклу, что произошли некоторые высокоуровневые события. Например, если мы запросили подключение сокета к другому хосту, мы знаем, что соединение установлено, когда сокет впервые становится доступным для записи (в этот момент можно писать в него, рассчитывая на успех). Подразумеваемые высокоуровневые события:

| Событие | Описание |
| --- | --- |
| `handle_connect()` | Подразумевается первым событием записи |
| `handle_close()` | Подразумевается событием чтения, когда данные недоступны |
| `handle_accept()` | Подразумевается событием чтения на слушающем сокете |

В процессе асинхронной обработки методы [`readable()`](https://python-all.ru/3.0/library/asyncore.html#asyncore.dispatcher.readable) и [`writable()`](https://python-all.ru/3.0/library/asyncore.html#asyncore.dispatcher.writable) каждого сопоставленного канала используются для определения, нужно ли добавить сокет канала в список каналов для опроса `select` или `poll` на предмет событий чтения и записи.

Таким образом, набор событий канала шире, чем базовые события сокета. Полный набор методов, которые можно переопределить в вашем подклассе, приведён ниже:

#### `[asyncore.dispatcher.handle_read]handle_read()`

Вызывается, когда асинхронный цикл обнаруживает, что вызов

`read()`

на сокете канала завершится успешно.

#### `[asyncore.dispatcher.handle_write]handle_write()`

Вызывается, когда асинхронный цикл обнаруживает, что сокет, доступный для записи, можно записать. Часто этот метод реализует необходимую буферизацию для производительности. Например:

```python
def handle_write(self):
    sent = self.send(self.buffer)
    self.buffer = self.buffer[sent:]
```

#### `[asyncore.dispatcher.handle_expt]handle_expt()`

Вызывается при наличии внеполосных данных (OOB) для сокетного соединения. Это почти никогда не происходит, так как OOB поддерживается слабо и редко используется.

#### `[asyncore.dispatcher.handle_connect]handle_connect()`

Вызывается, когда сокет активного инициатора действительно устанавливает соединение. Может, например, отправить приветственный баннер или инициировать согласование протокола с удалённой конечной точкой.

#### `[asyncore.dispatcher.handle_close]handle_close()`

Вызывается при закрытии сокета.

#### `[asyncore.dispatcher.handle_error]handle_error()`

Вызывается, когда возникает исключение, которое иначе не обрабатывается. Версия по умолчанию выводит сокращённую трассировку.

#### `[asyncore.dispatcher.handle_accept]handle_accept()`

Вызывается на прослушивающих каналах (пассивных открывателях), когда можно установить соединение с новой удалённой конечной точкой, которая выполнила вызов

[`connect()`](https://python-all.ru/3.0/library/asyncore.html#asyncore.dispatcher.connect)

для данной локальной конечной точки.

#### `[asyncore.dispatcher.readable]readable()`

Вызывается на каждом проходе асинхронного цикла, чтобы определить, нужно ли добавить сокет канала в список, на котором могут происходить события чтения. Метод по умолчанию просто возвращает

`True`

, указывая, что по умолчанию все каналы заинтересованы в событиях чтения.

#### `[asyncore.dispatcher.writable]writable()`

Вызывается на каждом проходе асинхронного цикла, чтобы определить, нужно ли добавить сокет канала в список, на котором могут происходить события записи. Метод по умолчанию просто возвращает

`True`

, указывая, что по умолчанию все каналы заинтересованы в событиях записи.

Кроме того, каждый канал делегирует или расширяет многие методы сокета. Большинство из них почти идентичны своим сокетным аналогам.

#### `[asyncore.dispatcher.create_socket]create_socket(family, type)`

Это идентично созданию обычного сокета и использует те же параметры создания. Обратитесь к документации

[`socket`](https://python-all.ru/3.0/library/socket.html#module-socket)

за информацией о создании сокетов.

#### `[asyncore.dispatcher.connect]connect(address)`

Как и для обычного объекта сокета,

*address*

– это кортеж, первый элемент которого – хост для подключения, а второй – номер порта.

#### `[asyncore.dispatcher.send]send(data)`

Отправляет

*data*

на удалённый узел сокета.

#### `[asyncore.dispatcher.recv]recv(buffer_size)`

Читает не более

*buffer\_size*

байт из удалённой конечной точки сокета. Пустая строка означает, что канал был закрыт с другого конца.

#### `[asyncore.dispatcher.listen]listen(backlog)`

Ожидает входящие соединения на сокете. Аргумент

*backlog*

задаёт максимальное количество соединений в очереди и должен быть не менее 1; максимальное значение зависит от системы (обычно 5).

#### `[asyncore.dispatcher.bind]bind(address)`

Привязывает сокет к адресу

*address*

. Сокет не должен быть уже привязан. (Формат

*address*

зависит от семейства адресов – см. выше.) Чтобы пометить сокет как повторно используемый (установив опцию

`SO_REUSEADDR`

), вызовите у объекта

[`dispatcher`](https://python-all.ru/3.0/library/asyncore.html#asyncore.dispatcher)

метод

`set_reuse_addr()`

.

#### `[asyncore.dispatcher.accept]accept()`

Принимает соединение. Сокет должен быть привязан к адресу и находиться в состоянии ожидания соединений. Возвращаемое значение – пара

`(conn, address)`

, где

*conn*

– это

*новый*

объект сокета, который можно использовать для отправки и получения данных по соединению, а

*address*

– это адрес, привязанный к сокету на другом конце соединения.

#### `[asyncore.dispatcher.close]close()`

Закрывает сокет. Все последующие операции с объектом сокета будут завершаться ошибкой. Удалённый узел больше не будет получать данные (после отправки данных из очереди). Сокеты автоматически закрываются при сборке мусора.

#### `[asyncore.file_dispatcher]class asyncore.file_dispatcher`

file\_dispatcher принимает файловый дескриптор или файловый объект вместе с необязательным аргументом map и оборачивает его для использования с функциями

`poll`

или

`loop`

. Если передан файловый объект или что-либо с методом

`fileno`

, этот метод будет вызван и передан в конструктор

[`file_wrapper`](https://python-all.ru/3.0/library/asyncore.html#asyncore.file_wrapper)

. Доступность: UNIX.

#### `[asyncore.file_wrapper]class asyncore.file_wrapper`

file\_wrapper принимает целочисленный файловый дескриптор и вызывает

[`os.dup()`](https://python-all.ru/3.0/library/os.html#os.dup)

для дублирования дескриптора, чтобы исходный дескриптор можно было закрыть независимо от file\_wrapper. Этот класс реализует достаточное количество методов для эмуляции сокета для использования классом

[`file_dispatcher`](https://python-all.ru/3.0/library/asyncore.html#asyncore.file_dispatcher)

. Доступно: UNIX.

## asyncore Пример базового HTTP-клиента

Вот очень простой HTTP-клиент, который использует класс [`dispatcher`](https://python-all.ru/3.0/library/asyncore.html#asyncore.dispatcher) для реализации обработки сокетов:

```python
import asyncore, socket

class http_client(asyncore.dispatcher):

    def __init__(self, host, path):
        asyncore.dispatcher.__init__(self)
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect( (host, 80) )
        self.buffer = bytes('GET %s HTTP/1.0\r\n\r\n' % path, 'ascii')

    def handle_connect(self):
        pass

    def handle_close(self):
        self.close()

    def handle_read(self):
        print(self.recv(8192))

    def writable(self):
        return (len(self.buffer) > 0)

    def handle_write(self):
        sent = self.send(self.buffer)
        self.buffer = self.buffer[sent:]

c = http_client('www.python.org', '/')

asyncore.loop()
```
