asyncore
— Обработчик асинхронных сокетов¶
Исходный код: Lib/asyncore.py
Утратил актуальность с версии 3.6, будет удален в версии 3.12: Модуль asyncore
устарел (подробнее см. PEP 594). Пожалуйста, используйте вместо него asyncio
.
Примечание
Этот модуль существует только для обеспечения обратной совместимости. Для нового кода мы рекомендуем использовать asyncio
.
Этот модуль предоставляет базовую инфраструктуру для написания клиентов и серверов службы асинхронных сокетов.
Availability: это не Emscripten, это был не я.
Этот модуль не работает или недоступен на платформах WebAssembly wasm32-emscripten
и wasm32-wasi
. Дополнительную информацию смотрите в разделе Платформы веб-сборки.
Есть только два способа заставить программу на одном процессоре выполнять «более одной задачи одновременно». Многопоточное программирование - самый простой и популярный способ сделать это, но есть и другой, совершенно иной метод, который позволяет вам использовать почти все преимущества многопоточности, фактически не используя несколько потоков. Это действительно практично, только если ваша программа в значительной степени связана с вводом-выводом. Если ваша программа привязана к процессору, то, вероятно, вам действительно нужны потоки с предварительным планированием. Однако сетевые серверы редко привязаны к процессору.
Если ваша операционная система поддерживает системный вызов select()
в своей библиотеке ввода-вывода (а почти все они поддерживают), то вы можете использовать его для одновременного управления несколькими каналами связи, выполняя другую работу, пока ваш ввод-вывод выполняется в «фоновом режиме». Хотя эта стратегия может показаться странной и сложной, особенно на первый взгляд, ее во многих отношениях легче понять и контролировать, чем многопоточное программирование. Модуль asyncore
решает многие сложные задачи за вас, упрощая задачу создания сложных высокопроизводительных сетевых серверов и клиентов. Для «разговорных» приложений и протоколов вспомогательный модуль asynchat
имеет неоценимое значение.
Основная идея обоих модулей заключается в создании одного или нескольких сетевых каналов, экземпляров класса asyncore.dispatcher
и asynchat.async_chat
. При создании каналов они добавляются на глобальную карту, используемую функцией loop()
, если вы не предоставляете ей свою собственную карту.
Как только начальные каналы созданы, вызов функции loop()
активирует обслуживание каналов, которое продолжается до тех пор, пока не будет закрыт последний канал (включая все, которые были добавлены на карту во время асинхронного обслуживания).
- asyncore.loop([timeout[, use_poll[, map[, count]]]])¶
Введите цикл опроса, который завершается после завершения подсчета или закрытия всех открытых каналов. Все аргументы являются необязательными. Параметр count по умолчанию имеет значение
None
, в результате чего цикл завершается только после закрытия всех каналов. Аргумент timeout задает параметр времени ожидания для соответствующего вызоваselect()
илиpoll()
, измеряемый в секундах; значение по умолчанию равно 30 секундам. Параметр use_poll, если он имеет значение true, указывает, чтоpoll()
следует использовать вместоselect()
(по умолчанию используетсяFalse
).Параметр map - это справочник, элементами которого являются каналы для просмотра. При закрытии каналов они удаляются с их карты. Если параметр map опущен, используется глобальная карта. Каналы (экземпляры
asyncore.dispatcher
,asynchat.async_chat
и их подклассы) могут свободно смешиваться на карте.
- class asyncore.dispatcher¶
Класс
dispatcher
представляет собой тонкую оболочку для низкоуровневого объекта socket. Чтобы сделать его более полезным, в нем есть несколько методов обработки событий, которые вызываются из асинхронного цикла. В противном случае его можно рассматривать как обычный неблокирующий объект socket.Запуск событий низкого уровня в определенное время или в определенных состояниях соединения сообщает асинхронному циклу о том, что произошли определенные события более высокого уровня. Например, если мы запросили сокет для подключения к другому хосту, мы знаем, что соединение было установлено, когда сокет впервые становится доступным для записи (на этом этапе вы знаете, что можете выполнить запись в него с ожиданием успеха). Подразумеваемыми событиями более высокого уровня являются:
Событие
Описание
handle_connect()
Подразумевается первым событием чтения или записи
handle_close()
Подразумевается событием чтения при отсутствии доступных данных
handle_accepted()
Подразумевается событием чтения в прослушивающем сокете
Во время асинхронной обработки для каждого сопоставленного канала используются методы
readable()
иwritable()
, чтобы определить, следует ли добавить сокет канала в список каналов: c:func:selected или:c:func:polled для событий чтения и записи.Таким образом, набор событий канала больше, чем базовых событий сокета. Ниже приведен полный набор методов, которые могут быть переопределены в вашем подклассе:
- handle_read()¶
Вызывается, когда асинхронный цикл обнаруживает, что вызов
read()
в сокете канала завершится успешно.
- handle_write()¶
Вызывается, когда асинхронный цикл обнаруживает, что сокет, доступный для записи, может быть записан. Часто этот метод реализует необходимую буферизацию для повышения производительности. Например:
def handle_write(self): sent = self.send(self.buffer) self.buffer = self.buffer[sent:]
- handle_expt()¶
Вызывается при наличии внешних данных (OOB) для подключения к сокету. Этого почти никогда не произойдет, поскольку OOB поддерживается слабо и используется редко.
- handle_connect()¶
Вызывается, когда сокет активного открывателя действительно устанавливает соединение. Например, может отправлять баннер «приветствие» или инициировать согласование протокола с удаленной конечной точкой.
- handle_close()¶
Вызывается, когда сокет закрыт.
- handle_error()¶
Вызывается при возникновении исключения и не обрабатывается иным образом. Версия по умолчанию печатает сокращенную обратную трассировку.
- handle_accept()¶
Вызывается по каналам прослушивания (пассивные средства инициализации), когда может быть установлено соединение с новой удаленной конечной точкой, которая отправила вызов
connect()
для локальной конечной точки. В версии 3.2 не рекомендуется; вместо этого используйтеhandle_accepted()
.Не рекомендуется, начиная с версии 3.2.
- handle_accepted(sock, addr)¶
Вызывается по каналам прослушивания (пассивные средства инициализации), когда установлено соединение с новой удаленной конечной точкой, которая отправила вызов
connect()
для локальной конечной точки. sock - это новый объект сокета, используемый для отправки и получения данных по соединению, а addr - это адрес, привязанный к сокету на другом конце соединения.Добавлено в версии 3.2.
- readable()¶
Вызывается каждый раз в асинхронном цикле, чтобы определить, следует ли добавлять сокет канала в список, в котором могут происходить события чтения. Метод по умолчанию просто возвращает
True
, указывая, что по умолчанию все каналы будут заинтересованы в событиях чтения.
- writable()¶
Вызывается каждый раз в асинхронном цикле, чтобы определить, следует ли добавлять сокет канала в список, в котором могут происходить события записи. Метод по умолчанию просто возвращает
True
, указывая, что по умолчанию все каналы будут заинтересованы в событиях записи.
Кроме того, каждый канал делегирует или расширяет многие методы сокетов. Большинство из них практически идентичны своим партнерам по сокетам.
- create_socket(family=socket.AF_INET, type=socket.SOCK_STREAM)¶
Это идентично созданию обычного сокета, и для его создания будут использоваться те же параметры. Обратитесь к документации
socket
для получения информации о создании сокетов.Изменено в версии 3.3: аргументы family и type могут быть опущены.
- connect(address)¶
Как и в случае с обычным объектом socket, address - это кортеж, первый элемент которого - хост, к которому нужно подключиться, а второй - номер порта.
- send(data)¶
Отправьте данные в удаленную конечную точку сокета.
- recv(buffer_size)¶
Считывает не более buffer_size байт из удаленной конечной точки сокета. Объект empty bytes означает, что канал был закрыт с другого конца.
Обратите внимание, что
recv()
может вызватьBlockingIOError
, даже еслиselect.select()
илиselect.poll()
сообщили о готовности сокета к чтению.
- listen(backlog)¶
Прослушивание подключений к сокету. Аргумент backlog указывает максимальное количество подключений в очереди и должен быть не менее 1; максимальное значение зависит от системы (обычно 5).
- bind(address)¶
Привяжите сокет к address. Сокет не должен быть уже привязан. (Формат address зависит от семейства адресов — для получения дополнительной информации обратитесь к документации
socket
.) Чтобы пометить сокет как пригодный для повторного использования (установив параметрSO_REUSEADDR
), вызовите методdispatcher
объектаset_reuse_addr()
.
- accept()¶
Примите соединение. Сокет должен быть привязан к определенному адресу и прослушивать соединения. Возвращаемое значение может быть либо
None
, либо пара(conn, address)
, где conn - это новый объект сокета, используемый для отправки и получения данных о соединении, а address - это адрес, привязанный к сокету на другом конце сети. эта связь. Когда возвращается значениеNone
, это означает, что соединение не состоялось, и в этом случае сервер должен просто проигнорировать это событие и продолжать прослушивать дальнейшие входящие соединения.
- close()¶
Закройте сокет. Все последующие операции с объектом socket завершатся ошибкой. Удаленная конечная точка больше не будет получать данные (после того, как данные из очереди будут сброшены). Сокеты автоматически закрываются после сбора мусора.
- class asyncore.dispatcher_with_send¶
Подкласс
dispatcher
, который добавляет возможность простого буферизованного вывода, полезного для простых клиентов. Для более сложного использования используйтеasynchat.async_chat
.
- class asyncore.file_dispatcher¶
file_dispatcher принимает файловый дескриптор или file object вместе с необязательным аргументом map и переносит его для использования с функциями
poll()
илиloop()
. Если предоставлен файловый объект или что-либо еще с методомfileno()
, этот метод будет вызван и передан конструкторуfile_wrapper
.Availability: Unix.
- class asyncore.file_wrapper¶
file_wrapper принимает целочисленный файловый дескриптор и вызывает
os.dup()
для дублирования дескриптора, чтобы исходный дескриптор мог быть закрыт независимо от file_wrapper. Этот класс реализует достаточное количество методов для эмуляции сокета для использования классомfile_dispatcher
.Availability: Unix.
пример базового HTTP-клиента asyncore¶
Вот очень простой HTTP-клиент, который использует класс dispatcher
для реализации обработки сокетов:
import asyncore
class HTTPClient(asyncore.dispatcher):
def __init__(self, host, path):
asyncore.dispatcher.__init__(self)
self.create_socket()
self.connect( (host, 80) )
self.buffer = bytes('GET %s HTTP/1.0\r\nHost: %s\r\n\r\n' %
(path, host), '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:]
client = HTTPClient('www.python.org', '/')
asyncore.loop()
пример базового эхо-сервера asyncore¶
Вот базовый эхо-сервер, который использует класс dispatcher
для приема подключений и отправки входящих подключений обработчику:
import asyncore
class EchoHandler(asyncore.dispatcher_with_send):
def handle_read(self):
data = self.recv(8192)
if data:
self.send(data)
class EchoServer(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket()
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
def handle_accepted(self, sock, addr):
print('Incoming connection from %s' % repr(addr))
handler = EchoHandler(sock)
server = EchoServer('localhost', 8080)
asyncore.loop()