asyncore
— controlador de socket asincrónico¶
Código fuente: Lib/asyncore.py
Obsoleto desde la versión 3.6: asyncore
will be removed in Python 3.12
(see PEP 594 for details).
Please use asyncio
instead.
Nota
Este módulo solo existe para compatibilidad con versiones anteriores. Para el nuevo código recomendamos usar asyncio
.
Este módulo proporciona la infraestructura básica para escribir servicio de socket asincrónicos, clientes y servidores.
Sólo hay dos maneras de que un programa en un solo procesador haga «más de una cosa a la vez». La programación multiproceso es la forma más sencilla y popular de hacerlo, pero hay otra técnica muy diferente, que le permite tener casi todas las ventajas de multiproceso, sin usar realmente varios subprocesos. Es realmente sólo práctico si su programa está en gran parte limitado por el I/O. Si el programa está limitado por el procesador, los subprocesos programados preventivos son probablemente lo que realmente necesita. Sin embargo, los servidores de red rara vez están limitado al procesador.
Si su sistema operativo es compatible con la llamada del sistema select()
en su biblioteca de I/O (y casi todos lo son), puede usarla para hacer malabares con varios canales de comunicación a la vez; haciendo otro trabajo mientras su I/O está teniendo lugar en el «fondo». Aunque esta estrategia puede parecer extraña y compleja, especialmente al principio, es en muchos sentidos más fácil de entender y controlar que la programación multiproceso. El módulo asyncore
resuelve muchos de los problemas difíciles para usted, haciendo que la tarea de construir sofisticados servidores de red de alto rendimiento y clientes sea fácil. Para aplicaciones y protocolos «conversacionales», el módulo complementario asynchat
es invaluable.
La idea básica detrás de ambos módulos es crear uno o más canales de red, instancias de clase asyncore.dispatcher
y asynchat.async_chat
. La creación de los canales los agrega a un mapa global, utilizado por la función loop()
si no lo proporciona con su propio map.
Una vez creados los canales iniciales, llamar a la función loop()
activa el servicio de canal, que continúa hasta que se cierra el último canal (incluido el que se ha agregado al mapa durante el servicio asincrónico).
-
asyncore.
loop
([timeout[, use_poll[, map[, count]]]])¶ Ingresa un bucle de sondeo que termina después de que se hayan cerrado los pases de conteo o todos los canales abiertos. Todos los argumentos son opcionales. El parámetro count tiene como valor predeterminado
None
, lo que da como resultado que el bucle termine solo cuando se hayan cerrado todos los canales. El argumento timeout establece el parámetro de tiempo de espera para la llamada adecuada aselect()
opoll()
, medida en segundos; el valor predeterminado es 30 segundos. El parámetro use_poll, si es true, indica quepoll()
debe utilizarse en lugar deselect()
(el valor predeterminado esFalse
).El parámetro map es un diccionario cuyos elementos son los canales a observar. A medida que se cierran los canales, se eliminan del mapa. Si se omite map, se utiliza un mapa global. Los canales (instancias de
asyncore.dispatcher
,asynchat.async_chat
y subclases de los mismos) se pueden mezclar libremente en el mapa.
-
class
asyncore.
dispatcher
¶ La clase
dispatcher
es un contenedor fino alrededor de un objeto de socket de bajo nivel. Para hacerlo más útil, tiene algunos métodos para el control de eventos que se llaman desde el bucle asincrónico. De lo contrario, se puede tratar como un objeto de socket normal sin bloqueo.La activación de eventos de bajo nivel en determinados momentos o en determinados estados de conexión indica al bucle asincrónico que se han producido ciertos eventos de nivel superior. Por ejemplo, si hemos pedido un socket para conectarse a otro host, sabemos que la conexión se ha realizado cuando el socket se vuelve grabable por primera vez (en este punto sabe que puede escribir a él con la expectativa de éxito). Los eventos de nivel superior implícitos son:
Evento
Descripción
handle_connect()
Implícito en el primer proceso de lectura o escritura
handle_close()
Implícito en un evento de lectura sin datos disponibles
handle_accepted()
Implícito en un evento de lectura en un socket de escucha
Durante el procesamiento asincrónico, se utilizan los métodos
readable()
ywritable()
de cada canal asignado para determinar si el socket del canal deberían ser agregados a la lista de canalesseleccionados
oencuestados
para eventos de lectura y escritura.Por lo tanto, el conjunto de eventos de canal es mayor que los eventos básicos del socket. El conjunto completo de métodos que se pueden invalidar en la subclase es el siguiente:
-
handle_read
()¶ Se llama cuando el bucle asincrónico detecta que una llamada
read()
en el socket del canal tendrá éxito.
-
handle_write
()¶ Se llama cuando el bucle asincrónico detecta que se puede escribir un socket grabable. A menudo, este método implementará el almacenamiento en búfer necesario para el rendimiento. Por ejemplo:
def handle_write(self): sent = self.send(self.buffer) self.buffer = self.buffer[sent:]
-
handle_expt
()¶ Se llama cuando hay datos fuera de banda (OOB) para una conexión de socket. Esto casi nunca sucederá, ya que OOB es tenuemente compatible y rara vez se utiliza.
-
handle_connect
()¶ Se llama cuando el socket del abridor activo realmente hace una conexión. Puede enviar un banner de «bienvenido» o iniciar una negociación de protocolo con el punto de conexión remoto, por ejemplo.
-
handle_close
()¶ Se llama cuando el socket está cerrado.
-
handle_error
()¶ Se llama cuando se genera una excepción y no se controla de otro modo. La versión predeterminada imprime un traceback condensado.
-
handle_accept
()¶ Se llama en los canales de escucha (abridores pasivos) cuando se puede establecer una conexión con un nuevo punto de conexión remoto que ha emitido una llamada
connect()
para el punto de conexión local. En desuso en la versión 3.2; usehandle_accepted()
en su lugar.Obsoleto desde la versión 3.2.
-
handle_accepted
(sock, addr)¶ Se llama en los canales de escucha (abridores pasivos) cuando se ha establecido una conexión con un nuevo punto de conexión remoto que ha emitido una llamada
connect()
para el punto de conexión local. sock es un objeto de socket new utilizable para enviar y recibir datos en la conexión, y addr es la dirección enlazada al socket en el otro extremo de la conexión.Nuevo en la versión 3.2.
-
readable
()¶ Se llama en cada momento alrededor del bucle asincrónico para determinar si se debe agregar el socket de un canal a la lista en la que se pueden producir eventos de lectura. El método predeterminado simplemente retorna
True
, lo que indica que, de forma predeterminada, todos los canales estarán interesados en eventos de lectura.
-
writable
()¶ Se llama cada vez alrededor del bucle asincrónico para determinar si se debe agregar el socket de un canal a la lista en la que se pueden producir eventos de escritura. El método predeterminado simplemente retorna
True
, lo que indica que, de forma predeterminada, todos los canales estarán interesados en eventos de escritura.
Además, cada canal delega o extiende muchos de los métodos de socket. La mayoría de estos son casi idénticos a sus socios de socket.
-
create_socket
(family=socket.AF_INET, type=socket.SOCK_STREAM)¶ Esto es idéntico a la creación de un socket normal y usará las mismas opciones para la creación. Consulte la documentación
socket
para obtener información sobre la creación de sockets.Distinto en la versión 3.3: Los argumentos family y type se pueden omitir.
-
connect
(address)¶ Al igual que con el objeto de socket normal, address es una tupla con el primer elemento al que se va a conectar el host y el segundo el número de puerto.
-
send
(data)¶ Envía data al punto final remoto del socket.
-
recv
(buffer_size)¶ Lee como máximo los bytes buffer_size desde el punto final remoto del socket. Un objeto bytes vacío implica que el canal se ha cerrado desde el otro extremo.
Tenga en cuenta que
recv()
puede elevarBlockingIOError
, aunqueselect.select()
oselect.poll()
ha informado del socket listo para la lectura.
-
listen
(backlog)¶ Escucha las conexiones realizadas al socket. El argumento backlog especifica el número máximo de conexiones en cola y debe ser al menos 1; el valor máximo depende del sistema (normalmente 5).
-
bind
(address)¶ Enlaza el socket a address. El socket no debe estar enlazado ya. (El formato de address depende de la familia de direcciones — consulte la documentación
socket
para obtener más información.) Para marcar el socket como reutilizable (estableciendo la opciónSO_REUSEADDR
), llame al métodoset_reuse_addr()
del objetodispatcher
.
-
accept
()¶ Acepta una conexión. El socket debe estar enlazado a una dirección y escuchar las conexiones. El valor retornado puede ser
None
o un par(conn, address)
donde conn es un objeto de socket new utilizable para enviar y recibir datos en la conexión, y address es la dirección enlazada al socket en el otro extremo de la conexión. Cuando se retornaNone
significa que la conexión no se llevó a cabo, en cuyo caso el servidor debe ignorar este evento y seguir escuchando otras conexiones entrantes.
-
close
()¶ Cierra el socket. Se producirá un error en todas las operaciones futuras en el objeto de socket. El punto final remoto no recibirá más datos (después de vaciar los datos en cola). Los sockets se cierran automáticamente cuando se recogen como elementos no utilizados.
-
-
class
asyncore.
dispatcher_with_send
¶ Una subclase
dispatcher
que agrega capacidad de salida almacenada en búfer simple, útil para clientes simples. Para un uso más sofisticado, utiliceasynchat.async_chat
.
-
class
asyncore.
file_dispatcher
¶ Un file_dispatcher toma un descriptor de archivo o file object junto con un argumento de mapa opcional y lo ajusta para su uso con las funciones
poll()
oloop()
. Si se proporciona un objeto de archivo o cualquier cosa con un métodofileno()
, ese método se llamará y se pasará al constructorfile_wrapper
.Disponibilidad: Unix.
-
class
asyncore.
file_wrapper
¶ Un file_wrapper toma un descriptor de archivo entero y llama a
os.dup()
para duplicar el identificador de modo que el identificador original se pueda cerrar independientemente del file_wrapper. Esta clase implementa métodos suficientes emulando un socket para su uso por la clasefile_dispatcher
.Disponibilidad: Unix.
Ejemplo asyncore de cliente HTTP básico¶
Aquí hay una llamada básica al cliente HTTP que usa la clase dispatcher
para implementar su controlador de socket:
import asyncore
class HTTPClient(asyncore.dispatcher):
def __init__(self, host, path):
asyncore.dispatcher.__init__(self)
self.create_socket()
self.connect( (host, 80) )
self.buffer = bytes('GET %s HTTP/1.0\r\nHost: %s\r\n\r\n' %
(path, host), 'ascii')
def handle_connect(self):
pass
def handle_close(self):
self.close()
def handle_read(self):
print(self.recv(8192))
def writable(self):
return (len(self.buffer) > 0)
def handle_write(self):
sent = self.send(self.buffer)
self.buffer = self.buffer[sent:]
client = HTTPClient('www.python.org', '/')
asyncore.loop()
Ejemplo asyncore de servidor de eco básico¶
Aquí hay un servidor de eco básico que utiliza la clase dispatcher
para aceptar conexiones y distribuye las conexiones entrantes a un controlador:
import asyncore
class EchoHandler(asyncore.dispatcher_with_send):
def handle_read(self):
data = self.recv(8192)
if data:
self.send(data)
class EchoServer(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket()
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
def handle_accepted(self, sock, addr):
print('Incoming connection from %s' % repr(addr))
handler = EchoHandler(sock)
server = EchoServer('localhost', 8080)
asyncore.loop()