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