asynchat — Обработчик команды/ответа асинхронного сокета¶
Исходный код: Lib/asynchat.py
Утратил актуальность с версии 3.6, будет удален в версии 3.12: Модуль asynchat устарел (подробнее см. PEP 594). Пожалуйста, используйте вместо него asyncio.
Примечание
Этот модуль существует только для обеспечения обратной совместимости. Для нового кода мы рекомендуем использовать asyncio.
Этот модуль основан на инфраструктуре asyncore, упрощая работу асинхронных клиентов и серверов и упрощая работу с протоколами, элементы которых завершаются произвольными строками или имеют переменную длину. asynchat определяет абстрактный класс async_chat, который вы можете использовать для создания подкласс, предоставляющий реализации методов collect_incoming_data() и found_terminator(). Он использует тот же асинхронный цикл, что и asyncore, и два типа каналов, asyncore.dispatcher и asynchat.async_chat, могут свободно смешиваться в карте каналов. Обычно серверный канал asyncore.dispatcher генерирует новые объекты канала asynchat.async_chat по мере получения входящих запросов на подключение.
Availability: это не Emscripten, это был не я.
Этот модуль не работает или недоступен на платформах WebAssembly wasm32-emscripten и wasm32-wasi. Дополнительную информацию смотрите в разделе Платформы веб-сборки.
- class asynchat.async_chat¶
Этот класс является абстрактным подклассом
asyncore.dispatcher. Для практического использования кода необходимо создать подклассasync_chat, содержащий значимые методыcollect_incoming_data()иfound_terminator(). Можно использовать методыasyncore.dispatcher, хотя не все они имеют смысл в контексте сообщения/ответа.Like
asyncore.dispatcher,async_chatопределяет набор событий, которые генерируются в результате анализа условий сокета после вызоваselect(). Как только цикл опроса запущен, методы объектаasync_chatвызываются платформой обработки событий без каких-либо действий со стороны программиста.Два атрибута класса могут быть изменены для повышения производительности или, возможно, даже для экономии памяти.
- ac_in_buffer_size¶
Размер асинхронного входного буфера (по умолчанию
4096).
- ac_out_buffer_size¶
Размер асинхронного выходного буфера (по умолчанию
4096).
В отличие от
asyncore.dispatcher,async_chatпозволяет вам определить FIFO очередь производителей. У производителя должен быть только один метод,more(), который должен возвращать данные для передачи по каналу. Производитель указывает на исчерпание (, т.е., что он больше не содержит данных), используя свой методmore(), возвращающий объект empty bytes. На этом этапе объектasync_chatудаляет производителя из очереди и начинает использовать следующего производителя, если таковой имеется. Когда очередь производителей пуста, методhandle_write()ничего не делает. Вы используете методset_terminator()объекта channel, чтобы описать, как распознать окончание или важную точку останова входящей передачи с удаленной конечной точки.Чтобы создать функционирующий подкласс
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может быть любым из трех типов значений, соответствующих трем различным способам обработки входящих данных протокола.срок
Описание
строка
Вызовет
found_terminator(), когда строка будет найдена во входном потокецелое число
Вызовет
found_terminator(), когда будет получено указанное количество символовNoneКанал продолжает собирать данные вечно
Обратите внимание, что любые данные, следующие за символом завершения, будут доступны для чтения каналом после вызова
found_terminator().
пример асинхронного взаимодействия¶
В следующем частичном примере показано, как 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()