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

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

Утратил актуальность с версии 3.6, будет удален в версии 3.12: Модуль asynchat устарел (подробнее см. PEP 594). Пожалуйста, используйте вместо него asyncio.


Примечание

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

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

Availability: это не Emscripten, это был не я.

Этот модуль не работает или недоступен на платформах WebAssembly wasm32-emscripten и wasm32-wasi. Дополнительную информацию смотрите в разделе Платформы веб-сборки.

class asynchat.async_chat

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

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

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

ac_in_buffer_size

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

ac_out_buffer_size

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

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

Чтобы создать функционирующий подкласс async_chat, ваши методы ввода collect_incoming_data() и found_terminator() должны обрабатывать данные, которые канал получает асинхронно. Методы описаны ниже.

async_chat.close_when_done()

Помещает None в очередь производителя. Когда этот производитель удаляется из очереди, это приводит к закрытию канала.

async_chat.collect_incoming_data(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 может быть любым из трех типов значений, соответствующих трем различным способам обработки входящих данных протокола.

срок

Описание

строка

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

целое число

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

None

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

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

пример асинхронного взаимодействия

В следующем частичном примере показано, как 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()
Вернуться на верх