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