asyncore
— Асинхронный обработчик сокетов¶
Исходный код: Lib/asyncore.py
Не рекомендуется, начиная с версии 3.6: Пожалуйста, используйте asyncio
вместо этого модуля.
Примечание
Модуль существует только для обратной совместимости. Для нового кода
рекомендуется использовать asyncio
.
Модуль предоставляет базовую инфраструктуру для написания асинхронного сокета обслуживания клиентов и серверы.
Есть только два способа, чтобы программа на одном процессоре выполняла «более одного действия за раз». Многопоточное программирование - самый простой и популярный способ для этого, но есть еще один совершенно другой метод, который позволяет получить почти все преимущества многопоточности без использования нескольких потоков. Это действительно практично, если ваша программа в значительной степени связана с I/O. Если ваша программа связана с процессором, то упреждающие запланированные потоки, вероятно, являются тем, что вам действительно нужно. Однако сетевые серверы редко привязаны к процессору.
Если операционная система поддерживает системный вызов select()
в своей
библиотеке I/O (почти все это умеют), то можно использовать его для
жонглирования сразу несколькими каналами связи; выполнять другую работу, пока ваша
I/O находится в «фоновом режиме». Хотя эта стратегия может показаться
странной и сложной, особенно на первых порах, она во многом проще в понимании и
управлении, чем многопоточное программирование. Модуль asyncore
решает многие
сложные проблемы, делая задачу построения сложных высокопроизводительных
сетевых серверов и клиентов моментальной. Для «разговорчивых» приложений и
протоколов модуль asynchat
компаньона бесценен.
Основная идея обоих модулей - создать одну или несколько сетевых
каналов, экземпляров класса asyncore.dispatcher
и
asynchat.async_chat
. Создание каналов добавляет их в глобальную
карту, используемая функцией loop()
, если вы не предоставляете ей свой
собственный карты.
Как только начальный канал (каналы) созданы, вызывание функции loop()
активирует обслуживание канала, которое продолжается, пока последний канал
(включая любого, которые были добавлены к карте во время асинхронного
обслуживания) не закроется.
-
asyncore.
loop
([timeout[, use_poll[, map[, count]]]])¶ Введите цикл опроса, завершающийся после прохождения счетчика или закрытия всех открытых каналов. Все аргументы необязательны. Параметр count по умолчанию имеет значение
None
, в результате чего цикл завершается только после закрытия всех каналов. Аргумент timeout задает параметр timeout для соответствующегоselect()
илиpoll()
вызова, измеряемый в секундах; значение по умолчанию - 30 секунд. Параметр use_poll, если значение равно true, указывает на то, чтоpoll()
следует используемый вместоselect()
(значение по умолчанию -False
).Параметр map - это словарь, элементы которого являются отслеживаемыми каналами. По мере закрытия каналов они удаляются с карты. Если map пропущен, используемый глобальная карта. Каналы (сущности их
asyncore.dispatcher
,asynchat.async_chat
и подклассов) могут свободно смешиваться в карте.
-
class
asyncore.
dispatcher
¶ dispatcher
класс представляет собой тонкую обертку вокруг объекта низкоуровневого сокета. Чтобы сделать его более полезным, он имеет несколько методов для обработки событий, которые вызываются из асинхронного цикла. В противном случае его можно рассматривать как обычный неблокирующий сокетный объект.Запуск низкоуровневое событий в определенные моменты времени или в определенные состояние связи сообщает асинхронному контуру о том, что произошли определенные события более высокого уровня. Например, если мы попросили сокет подключиться к другому хосту, мы знаем, что соединение было выполнено, когда сокет становится записываемым впервые (в этот момент вы знаете, что вы можете написать ему с ожиданием успеха). Подразумеваемые события более высокого уровня
Событие Описание 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)¶ Как и в случае обычного объекта сокет, address представляет собой кортеж с первым элементом, к которому подключается хост, и вторым номером порта.
-
send
(data)¶ Отправить data в удаленную конечную точку сокета.
-
recv
(buffer_size)¶ Считывание не более buffer_size байтов из удаленной конечной точки сокет. Пустой байтовый объект подразумевает, что канал закрыт с другого конца.
Отметим, что
recv()
может поднятьBlockingIOError
, даже несмотря на то, чтоselect.select()
илиselect.poll()
сообщили о готовом к чтению сокет.
-
listen
(backlog)¶ Прослушивайте подключения к сокет. Аргумент backlog указывает максимальное число соединений в очереди и должен быть не менее 1; максимальное значение зависит от системы (обычно 5).
-
bind
(address)¶ Привяжите сокет к address. Эта сокет не должна быть привязана. (Формат address зависит от семейства адресов — для получения дополнительной информации см.
socket
документацию.) чтобы отметить сокет как повторно используемый (установите параметрSO_REUSEADDR
), вызовитеdispatcher
object’sset_reuse_addr()
метод.
-
accept
()¶ Примите связь. Этот сокет должен быть привязан к адресу и прослушивать подключения. Стоимость возвращает может быть или
None
или парой(conn, address)
, где conn - объект new сокет, применимый, чтобы послать и получить данные по связи, и address - адрес, связанный с сокет на другом конце связи. КогдаNone
возвращенный, это означает, что соединение не состоялось, в этом случае сервер должен просто игнорировать это событие и продолжать прослушивать дальнейшие входящие соединения.
-
close
()¶ Закройте сокет. Все будущие операции с объектом сокет завершатся неудачей. Удаленная конечная точка не получит больше данных (после сброса данных в очереди). Розетки автоматически закрываются при сборе мусора.
-
-
class
asyncore.
dispatcher_with_send
¶ Подкласс
dispatcher
, который добавляет простую буферизованную возможность вывода, полезно для простых клиентов. Для более сложного использованияasynchat.async_chat
.
-
class
asyncore.
file_dispatcher
¶ file_dispatcher принимает дескриптор файла или файловый объект вместе с необязательным аргументом карты и упаковывает его для использования с
poll()
или функциямиloop()
. Если указан объект файла или что-либо с c:func:fileno метод, то этот метод будет вызван и передан конструкторуfile_wrapper
.Availability: Unix.
-
class
asyncore.
file_wrapper
¶ file_wrapper принимает целочисленный дескриптор файла и вызывает
os.dup()
для дублирования дескриптора, чтобы исходный дескриптор мог быть закрыт независимо от file_wrapper. Этот класс осуществляет достаточный методы, чтобы подражать сокет для использованияfile_dispatcher
класс.Availability: Unix.
Asyncore пример базового HTTP-клиента¶
Очень базовый 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()