Spec-Zone.ru › Python 3.7

asynchat — Обработчик асинхронных команд/ответов сокета

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

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

Примечание

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

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

class asynchat.async_chat

Этот класс является абстрактным подклассом asyncore.dispatcher. Для практического использования кода необходимо наследовать от async_chat, предоставив осмысленные методы collect_incoming_data() и found_terminator(). Методы asyncore.dispatcher могут быть использованы, хотя не все имеют смысл в контексте сообщений/ответов.

Подобно asyncore.dispatcher, async_chat определяет набор событий, которые генерируются при анализе состояния сокета после вызова select(). После запуска цикла опроса методы объекта async_chat вызываются механизмом обработки событий без каких-либо действий со стороны программиста.

Для повышения производительности или, возможно, для экономии памяти, можно изменить два атрибута класса.

ac_in_buffer_size

Размер буфера асинхронного ввода (по умолчанию 4096).

ac_out_buffer_size

Размер буфера асинхронного вывода (по умолчанию 4096).

В отличие от asyncore.dispatcher, async_chat позволяет определить очередь FIFO производителей. Производитель должен иметь только один метод, more(), который должен возвращать данные для передачи по каналу. Производитель указывает исчерпание (т.е., что он не содержит больше данных), сделав метод more() возвращающим пустой байтовый объект. В этот момент объект async_chat удаляет производителя из очереди и начинает использовать следующего производителя, если таковой имеется. Когда очередь производителей пуста, метод handle_write() ничего не делает. Вы используете метод объекта канала set_terminator() для описания того, как распознать конец или важную точку останова входящей передачи от удалённого узла.

Для создания работоспособного подкласса async_chat ваши методы ввода collect_incoming_data() и found_terminator() должны обрабатывать данные, которые канал получает асинхронно. Методы описаны ниже.

async_chat.close_when_done()

Добавляет None в очередь производителей. При извлечении этого производителя из очереди канал закрывается.

async_chat.collect_incoming_data(data)

Вызывается с данными, содержащими произвольное количество полученных данных. Метод по умолчанию, который должен быть переопределён, вызывает исключение NotImplementedError.

async_chat.discard_buffers()

В критических ситуациях этот метод удалит любые данные, хранящиеся в буферах ввода и/или вывода, и очереди производителей.

async_chat.found_terminator()

Вызывается, когда входящий поток данных соответствует условию завершения, заданному set_terminator(). Метод по умолчанию, который должен быть переопределён, вызывает исключение NotImplementedError. Буферизованные входные данные должны быть доступны через атрибут экземпляра.

async_chat.get_terminator()

Возвращает текущее значение завершающего символа для канала.

async_chat.push(data)

Добавляет данные в очередь канала для обеспечения их передачи. Этого достаточно, чтобы канал записал данные в сеть, хотя для более сложных схем, таких как шифрование и фрагментация, можно использовать собственных производителей.

async_chat.push_with_producer(producer)

Принимает объект производителя и добавляет его в очередь производителей, связанную с каналом. После того, как все текущие производители будут исчерпаны, канал использует данные этого производителя, вызвав метод more() и отправит данные на удалённый узел.

async_chat.set_terminator(term)

Устанавливает условие завершения, которое необходимо распознать в канале. term может быть любого из трёх типов, соответствующих трём различным способам обработки входящих протокольных данных.

term

Описание

строка

Вызовет found_terminator() при обнаружении строки во входном потоке

целое число

Вызовет found_terminator() при получении указанного числа символов

None

Канал продолжает собирать данные бесконечно

Обратите внимание, что любые данные, следующие за завершающим символом, будут доступны для чтения каналом после вызова found_terminator().

Пример asynchat

Следующий частичный пример показывает, как HTTP-запросы можно читать с помощью async_chat. Веб-сервер может создавать объект http_request_handler для каждого входящего подключения клиента. Обратите внимание, что первоначально завершающий символ канала настроен на соответствие пустой строке в конце HTTP-заголовков, и флаг указывает, что читаются заголовки.

После прочтения заголовков, если запрос типа POST (указывает на то, что в входном потоке имеются дальнейшие данные), то используется заголовок Content-Length: для установки числового завершающего символа, чтобы прочитать правильное количество данных из канала.

Метод handle_request() вызывается после того, как все необходимые входные данные были обработаны, после установки завершающего символа канала на None для того, чтобы любые посторонние данные, отправленные веб-клиентом, игнорировались.

import asynchat

class http_request_handler(asynchat.async_chat):

    def __init__(self, sock, addr, sessions, log):
        asynchat.async_chat.__init__(self, sock=sock)
        self.addr = addr
        self.sessions = sessions
        self.ibuffer = []
        self.obuffer = b""
        self.set_terminator(b"\r\n\r\n")
        self.reading_headers = True
        self.handling = False
        self.cgi_data = None
        self.log = log

    def collect_incoming_data(self, data):
        """Buffer the data"""
        self.ibuffer.append(data)

    def found_terminator(self):
        if self.reading_headers:
            self.reading_headers = False
            self.parse_headers(b"".join(self.ibuffer))
            self.ibuffer = []
            if self.op.upper() == b"POST":
                clen = self.headers.getheader("content-length")
                self.set_terminator(int(clen))
            else:
                self.handling = True
                self.set_terminator(None)
                self.handle_request()
        elif not self.handling:
            self.set_terminator(None)  # browsers sometimes over-send
            self.cgi_data = parse(self.headers, b"".join(self.ibuffer))
            self.handling = True
            self.ibuffer = []
            self.handle_request()

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

Spec-Zone.ru

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