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()