Spec-Zone.ru › Python 2.7

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

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

Этот модуль основан на инфраструктуре 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 удаляет производителя из FIFO и начинает использовать следующего производителя, если таковой имеется. Когда очередь FIFO производителей пуста, метод handle_write() ничего не делает. Вы используете метод объекта канала set_terminator(), чтобы описать, как распознать конец или важную точку останова входящей передачи от удалённого узла.

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

async_chat.close_when_done()

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

async_chat.collect_incoming_data(data)

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

async_chat.discard_buffers()

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

async_chat.found_terminator()

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

async_chat.get_terminator()

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

async_chat.push(data)

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

async_chat.push_with_producer(producer)

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

async_chat.set_terminator(term)

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

term

Описание

строка

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

целое число

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

None

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

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

1. asynchat — Вспомогательные классы

class asynchat.fifo([list=None])

FIFO, хранящий данные, которые были добавлены приложением, но ещё не извлечены для записи в канал. fifo — список, используемый для хранения данных и/или производителей до их использования. Если аргумент list предоставлен, он должен содержать производителей или элементы данных, которые должны быть записаны в канал.

is_empty()

Возвращает True, если и только если FIFO пуст.

first()

Возвращает элемент, добавленный в FIFO последним.

push(data)

Добавляет данные (которые могут быть строкой или объектом производителя) в очередь FIFO производителей.

pop()

Если FIFO не пуст, возвращает True, first(), удаляя извлечённый элемент. Возвращает False, None для пустого FIFO.

2. Пример asynchat

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

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

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

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 = ""
        self.set_terminator("\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("".join(self.ibuffer))
            self.ibuffer = []
            if self.op.upper() == "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, "".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/2.7/library/asynchat.html

Spec-Zone.ru

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