asynchat
— Gestor de comandos/respuestas en sockets asíncronos¶
Código fuente: Lib/asynchat.py
Obsoleto desde la versión 3.6: asynchat
will be removed in Python 3.12
(see PEP 594 for details).
Please use asyncio
instead.
Nota
Este módulo existe únicamente por motivos de retrocompatibilidad. Para nuevo código, es recomendable usar asyncio
.
Este módulo se construye en la infraestructura de asyncore
, simplificando los clientes y servidores asíncronos y facilitando la gestión de protocolos cuyos elementos son terminados por cadenas de texto arbitrarias, o que son de longitud variable. asynchat
define la clase abstracta async_chat
de la que se debe heredar, implementado los métodos collect_incoming_data()
y found_terminator()
. Utiliza el mismo bucle asíncrono que asyncore
, y los dos tipos de canal, asyncore.dispatcher
y asynchat.async_chat
, se pueden mezclar libremente en el mapa de canal. Normalmente un canal de servidor asyncore.dispatcher
genera nuevos objetos de canal asynchat.async_chat
, al recibir peticiones de conexión entrantes.
-
class
asynchat.
async_chat
¶ Esta clase es una subclase abstracta de
asyncore.dispatcher
. Para el uso práctico del código se debe heredarasync_chat
, definiendo los métodos significativoscollect_incoming_data()
yfound_terminator()
. Los métodos deasyncore.dispatcher
se pueden utilizar, aunque no todos tienen sentido en un contexto de mensaje/respuesta.Al igual que
asyncore.dispatcher
,async_chat
define una serie de eventos generados por un análisis sobre las condiciones de _socket_, tras una llamada aselect()
. Una vez que el bucle de _polling_ haya sido iniciado, los métodos de los objetosasync_chat
son llamados por el _framework_ que procesa los eventos, sin que tengamos que programar ninguna acción a mayores.Se pueden modificar dos atributos de clase, para mejorar el rendimiento o incluso hasta para ahorrar memoria.
-
ac_in_buffer_size
¶ El tamaño del _buffer_ de entrada asíncrona (por defecto
4096
).
-
ac_out_buffer_size
¶ El tamaño del _buffer_ de salida asíncrona (por defecto
4096
).
Al contrario que
asyncore.dispatcher
,async_chat
permite definir una cola FIFO de productores (producers). Un productor necesita tener un solo método,more()
, que debe devolver los datos que se vayan a transmitir en el canal. Cuando el métodomore()
devuelve un objeto bytes vacío, significa que el productor ya se ha agotado (por ejemplo, que no contiene más datos). En este punto, el objetoasync_chat
elimina el productor de la cola y empieza a usar el siguiente productor, si existiese. Cuando la cola de productores está vacía, el métodohandle_write()
no hace nada. El métodoset_terminator()
de los objetos de canal se utiliza para describir cómo reconocer, en una transmisión entrante desde el punto remoto, el final de esta transmisión o un punto de ruptura importante en la misma.Para construir una subclase funcional de
async_chat
, los métodos de entradacollect_incoming_data()
andfound_terminator()
deben tratar los datos que el canal recibe asíncronamente. Los métodos se describen a continuación.-
-
async_chat.
close_when_done
()¶ Añade un
None
en la cola de productores. Cuando este productor se extrae de la cola, hace que el canal se cierre.
-
async_chat.
collect_incoming_data
(data)¶ Llamado con data, conteniendo una cantidad arbitraria de datos recibidos. El método por defecto, que debe ser reemplazado, lanza una excepción
NotImplementedError
.
-
async_chat.
discard_buffers
()¶ En situaciones de emergencia, este método descarta cualquier dato albergado en los búfers de entrada y/o salida y en la cola del productor.
-
async_chat.
found_terminator
()¶ Llamado cuando el flujo de datos de entrada coincide con la condición de finalización establecida por
set_terminator()
. El método por defecto, que debe ser reemplazado, lanza una excepciónNotImplementedError
. Los datos de entrada en búfer deberían estar disponibles a través de un atributo de instancia.
-
async_chat.
get_terminator
()¶ Retorna el terminador actual del canal.
-
async_chat.
push
(data)¶ Añade datos en la cola del canal para asegurarse de su transmisión. Esto es todo lo que se necesita hacer para que el canal envíe los datos a la red, aunque es posible usar productores personalizados en esquemas más complejos para implementar características como encriptación o fragmentación.
-
async_chat.
push_with_producer
(producer)¶ Takes a producer object and adds it to the producer queue associated with the channel. When all currently pushed producers have been exhausted the channel will consume this producer’s data by calling its
more()
method and send the data to the remote endpoint.
-
async_chat.
set_terminator
(term)¶ Establece la condición de finalización que será reconocida en este canal.
term
puede ser uno de los tres tipos de valores posibles, correspondientes a tres formas diferentes de tratar los datos de protocolo entrantes.término
Descripción
string
Llamará a
found_terminator()
cuando la cadena de caracteres se encuentre en el flujo de datos de entradainteger
Llamará a
found_terminator()
cuando el número de caracteres indicado se haya recibidoNone
El canal continúa recopilando datos indefinidamente
Téngase en cuenta que cualquier dato posterior al terminador estará disponible para ser leído por el canal después de llamar a
found_terminator()
.
Ejemplo de asynchat¶
El siguiente ejemplo parcial muestra cómo se pueden leer peticiones HTTP con async_chat
. Un servidor web podría crear un objeto http_request_handler
para cada conexión de cliente entrante. Téngase en cuenta que, inicialmente, el terminador del canal está configurado para detectar la línea vacía presente al final de las cabeceras HTTP, y una bandera indica que las cabeceras se están leyendo.
Una vez que las cabeceras se hayan leído, si la petición es de tipo POST (lo cual indica que hay más datos disponibles en el flujo de entrada), la cabecera Content-Length:
se utiliza para establecer un terminador numérico para leer la cantidad de datos correcta en el canal.
El método handle_request()
se llama una vez todas las entradas relevantes han sido serializadas (marshalled), tras establecer el terminador del canal a None
para asegurarse de que cualquier dato extraño enviado por el cliente web es ignorado.
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()