Содержание страницы
asynchat – Асинхронный обработчик команд/ответов через сокеты¶asynchat – Asynchronous socket command/response handler
Этот модуль основывается на инфраструктуре 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() возвращает пустую строку. В этот момент объект async_chat удаляет производителя из fifo и начинает использовать следующего, если таковой имеется. Когда очередь производителей пуста, метод 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._collect_incoming_data(data)¶
- Пример реализации процедуры сбора данных для использования вместе с _get_data() в задаваемой пользователем found_terminator().
- async_chat.discard_buffers()¶
- В экстренных случаях этот метод удаляет любые данные, находящиеся во входных и/или выходных буферах, а также в очереди производителей.
- async_chat.found_terminator()¶
- Вызывается, когда входящий поток данных соответствует условию завершения, установленному set_terminator(). Метод по умолчанию, который должен быть переопределен, вызывает исключение NotImplementedError. Буферизованные входные данные должны быть доступны через атрибут экземпляра.
- async_chat._get_data()¶
- Возвращает и очищает данные, полученные с помощью примера реализации _collect_incoming_data().
- async_chat.get_terminator()¶
- Возвращает текущий терминатор канала.
- async_chat.handle_close()¶
- Вызывается, когда канал закрыт. Метод по умолчанию молча закрывает сокет канала.
- async_chat.handle_read()¶
- Вызывается, когда в асинхронном цикле происходит событие чтения на сокете канала. Метод по умолчанию проверяет условие завершения, установленное set_terminator(), которое может быть либо появлением определённой строки во входном потоке, либо получением определённого количества символов. Когда терминатор найден, handle_read() вызывает метод found_terminator() после вызова collect_incoming_data() с данными, предшествующими завершающему условию.
- async_chat.handle_write()¶
- Вызывается, когда приложение может записать данные в канал. Метод по умолчанию вызывает метод initiate_send(), который, в свою очередь, вызывает refill_buffer() для сбора данных из очереди производителей, связанной с каналом.
- async_chat.push(data)¶
- Создаёт объект simple_producer (см. ниже), содержащий данные, и помещает его в очередь канала producer_fifo для обеспечения передачи. Это всё, что нужно сделать, чтобы канал записал данные в сеть, хотя можно использовать собственных производителей в более сложных схемах, например, для шифрования или разбиения на части.
- async_chat.push_with_producer(producer)¶
- Принимает объект производителя и добавляет его в очередь производителей, связанную с каналом. Когда все ранее помещенные производители будут исчерпаны, канал начнет потреблять данные этого производителя, вызывая его метод more(), и отправлять данные удаленной стороне.
- async_chat.readable()¶
- Должен возвращать True, чтобы канал был включён в набор каналов, проверяемых циклом select на читаемость.
- async_chat.refill_buffer()¶
- Пополняет выходной буфер, вызывая метод more() производителя в начале fifo. Если он истощён, производитель извлекается из fifo и активируется следующий. Если текущий производитель равен или становится None, канал закрывается.
- async_chat.set_terminator(term)¶
Устанавливает условие завершения для распознавания на канале. term может быть значением одного из трех типов, соответствующих трем различным способам обработки входящих протокольных данных.
терминатор Описание строка Будет вызывать found_terminator(), когда строка будет найдена во входном потоке. целое Будет вызывать found_terminator(), когда будет получено указанное количество символов. None Канал продолжает собирать данные бесконечно Обратите внимание, что любые данные, следующие за терминатором, будут доступны для чтения каналом после вызова found_terminator().
- async_chat.writable()¶
- Должен возвращать True, пока элементы остаются в очереди производителя (fifo) или канал подключен и его выходной буфер не пуст.
asynchat – вспомогательные классы и функции¶asynchat - Auxiliary Classes and Functions
- class asynchat.simple_producer(data[, buffer_size=512])¶
simple_producer принимает кусок данных и необязательный размер буфера. Повторные вызовы его метода more() возвращают последовательные куски данных, размер которых не превышает buffer_size.
- more()¶
- Выдаёт следующий кусок информации от производителя или возвращает пустую строку.
- class asynchat.fifo([list=None])¶
Каждый канал поддерживает fifo, содержащую данные, которые были помещены приложением, но ещё не извлечены для записи в канал. fifo представляет собой список, используемый для хранения данных и/или производителей до тех пор, пока они не потребуются. Если аргумент list передан, он должен содержать производителей или элементы данных для записи в канал.
- is_empty()¶
- Возвращает True, если и только если fifo пуст.
- push(data)¶
- Добавляет переданные данные (строку или объект-производитель) в producer fifo.
- pop()¶
- Если fifo не пуст, возвращает True, first(), удаляя извлечённый элемент. Если fifo пуст, возвращает False, None.
Модуль asynchat также определяет одну служебную функцию, которая может быть полезна при работе с сетью и анализе текста.
- asynchat.find_prefix_at_end(haystack, needle)¶
- Возвращает True, если строка haystack заканчивается любым непустым префиксом строки needle.
Пример asynchat¶asynchat Example
Следующий неполный пример показывает, как можно читать 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 = 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("".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()