Spec-Zone.ru › Python 3.7

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, если он равен true, указывает, что следует использовать poll() вместо select() (по умолчанию False).

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

END_OF_DOCUMENT_MARKER
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()

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

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 байт с удалённого конца сокета. Пустой объект bytes подразумевает, что канал был закрыт с другого конца.

Обратите внимание, что 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.

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

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

Spec-Zone.ru

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