Spec-Zone.ru › Python 3.5

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

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

Примечание

Этот модуль существует только для обратной совместимости. Для нового кода рекомендуется использовать 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 (first-in, first-out) производителей. Производитель должен иметь только один метод, 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)

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

async_chat.discard_buffers()

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

async_chat.found_terminator()

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

async_chat.get_terminator()

Возвращает текущий терминатор для канала.

async_chat.push(data)

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

async_chat.push_with_producer(producer)

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

async_chat.set_terminator(term)

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

term Описание
строка Вызовет found_terminator(), когда строка будет найдена в потоке ввода
целое число Вызовет found_terminator(), когда указанное количество символов будет получено
None Канал продолжает собирать данные бесконечно

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

1. Пример 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.5/library/asynchat.html

Spec-Zone.ru

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