asynchat — Асинхронный обработчик команд/ответов сокета
Исходный код: Lib/asynchat.py
Устарело начиная с версии 3.6: Пожалуйста, используйте asyncio вместо этого.
Примечание
Этот модуль существует только для обратной совместимости. Для нового кода рекомендуется использовать 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.Производитель должен иметь только один метод,
more(), который должен возвращать данные для передачи по каналу. Производитель указывает исчерпание (то есть, что он больше не содержит данных), сделав методmore()return empty bytes object. В этот момент объект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) -
Добавляет данные в очередь канала для обеспечения их передачи. Этого достаточно, чтобы канал записал данные в сеть, хотя можно использовать собственных производителей в более сложных схемах для реализации шифрования и разбиения на части, например.
-
async_chat.push_with_producer(producer) -
Принимает объект производителя и добавляет его в очередь производителей, связанную с каналом. Когда все текущие производители будут исчерпаны, канал будет потреблять данные этого производителя, вызывая его метод
more()и отправлять данные удаленному конечной точке.
-
async_chat.set_terminator(term) -
Устанавливает условие завершения, распознаваемое в канале.
termможет быть любого из трех типов значений, соответствующих трем различным способам обработки входящих данных протокола.term
Описание
строка
Вызовет
found_terminator(), когда строка будет найдена в потоке вводацелое число
Вызовет
found_terminator(), когда указанное количество символов будет полученоNoneКанал продолжает собирать данные вечно
Обратите внимание, что любые данные, следующие за условием завершения, будут доступны для чтения каналом после вызова
found_terminator().
Пример 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–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/library/asynchat.html