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’s set_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()