Spec-Zone.ru › Python 3.6

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

Исходный код: Lib/asyncore.py

Устаревшее начиная с версии 3.6: Пожалуйста, используйте asyncio вместо этого.

Примечание

Этот модуль существует только для обеспечения обратной совместимости. Для нового кода рекомендуется использовать asyncio.

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

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

Если ваша операционная система поддерживает системный вызов select() в своей библиотеке ввода-вывода (а почти все это поддерживают), то вы можете использовать его для одновременной обработки нескольких каналов связи, выполняя другие задачи, пока ввод-вывод происходит «на заднем плане». Хотя эта стратегия может показаться странной и сложной, особенно вначале, в некоторых отношениях она проще для понимания и контроля, чем мультипоточная программирование. Модуль asyncore решает многие сложные проблемы за вас, что делает задачу создания сложных высокопроизводительных сетевых серверов и клиентов легкой. Для «диалоговых» приложений и протоколов полезен связанный модуль asynchat.

Основная идея обоих модулей заключается в создании одного или нескольких сетевых каналов, экземпляров класса asyncore.dispatcher и asynchat.async_chat. Создание каналов добавляет их в глобальный массив, используемый функцией loop(), если вы не предоставите свой собственный массив.

После создания начального канала (ов) вызов функции loop() активирует обслуживание каналов, которое продолжается до закрытия последнего канала (включая любые, которые были добавлены в массив во время асинхронного обслуживания).

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

Введите цикл опроса, который завершается после прохождения count или закрытия всех открытых каналов. Все аргументы необязательны. Параметр count по умолчанию равен None, что приводит к завершению цикла только при закрытии всех каналов. Аргумент timeout устанавливает параметр таймаута для соответствующего вызова select() или poll(), измеряемого в секундах; по умолчанию 30 секунд. Параметр use_poll, если он истинный, указывает, что следует использовать poll() вместо select() (по умолчанию False).

Параметр map — это словарь, чьи элементы — это каналы, за которыми нужно следить. По мере закрытия каналов они удаляются из своего массива. Если map опущен, используется глобальный массив. Каналы (экземпляры asyncore.dispatcher, asynchat.async_chat и их подклассы) могут свободно смешиваться в массиве.

class asyncore.dispatcher

Класс dispatcher — это тонкий обертка вокруг низкоуровневого объекта сокета. Для повышения его полезности он имеет несколько методов обработки событий, которые вызываются из асинхронного цикла. В противном случае его можно рассматривать как обычный неблокирующий сокет.

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

Событие

Описание

handle_connect()

Подразумевается первым событием чтения или записи

handle_close()

Подразумевается событием чтения без доступных данных

handle_accepted()

Подразумевается событием чтения на сокете прослушивания

Во время асинхронной обработки методы readable() и writable() каждого сопоставленного канала используются для определения, следует ли добавлять сокет канала в список каналов, select()емых или poll()емых для событий чтения и записи.

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

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), вызовите метод set_reuse_addr() объекта dispatcher.

accept()

Принять подключение. Сокет должен быть привязан к адресу и ожидать подключений. Возвращаемое значение может быть либо None, либо парой (conn, address), где conn — это новый объект сокета, который можно использовать для отправки и получения данных по подключению, а address — адрес, привязанный к сокету на другом конце подключения. Если возвращается None, это означает, что подключение не произошло, в этом случае сервер должен просто проигнорировать это событие и продолжать прослушивать дальнейшие входящие подключения.

close()

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

class asyncore.dispatcher_with_send

Подкласс dispatcher, добавляющий простую буферизованную возможность вывода, полезную для простых клиентов. Для более сложных случаев используйте asynchat.async_chat.

class asyncore.file_dispatcher

file_dispatcher принимает дескриптор файла или объект файла вместе с необязательным аргументом отображения и оборачивает его для использования с функциями poll() или loop(). Если задан объект файла или что-то с методом fileno(), этот метод будет вызван и передан в конструктор file_wrapper. Доступность: UNIX.

class asyncore.file_wrapper

file_wrapper принимает целочисленный дескриптор файла и вызывает os.dup() для дублирования дескриптора, чтобы исходный дескриптор можно было закрыть независимо от file_wrapper. Этот класс реализует достаточные методы для имитации сокета для использования классом file_dispatcher. Доступность: UNIX.

18.6.1. Пример 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()

18.6.2. Пример сервера базового эха 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()

© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.6/library/asyncore.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API