18.7. asynchat
— Gestionnaire d’interfaces de connexion (socket) commande/réponse asynchrones¶
Code source :* Lib/asynchat.py
Obsolète depuis la version 3.6: Utilisez asyncio
à la place.
Note
Ce module n’existe que pour des raisons de rétrocompatibilité. Pour du code nouveau, l’utilisation de asyncio
est recommandée.
Ce module s’appuie sur l’infrastructure de asyncore
, en simplifiant les clients et serveurs asynchrones et en rendant plus facile la gestion de protocoles dont les éléments finissent par une chaine arbitraire, ou sont de longueur variable. asynchat
définit une classe abstraite async_chat
dont vous héritez, et qui fournit des implémentations des méthodes collect_incoming_data()
et found_terminator()
. Il utilise la même boucle asynchrone que asyncore
, et deux types de canaux, asyncore.dispatcher
et asynchat.async_chat
, qui peuvent être librement mélangés dans la carte des canaux. Habituellement, un canal de serveur asyncore.dispatcher
génère de nouveaux canaux d’objets asynchat.async_chat
à la réception de requêtes de connexion.
-
class
asynchat.
async_chat
¶ Cette classe est une sous-classe abstraite de
asyncore.dispatcher
. Pour en faire un usage pratique, vous devez créer une classe héritant deasync_chat
, et implémentant des méthodescollect_incoming_data()
etfound_terminator()
sensées. Les méthodes deasyncore.dispatcher
peuvent être utilisées, même si toutes n’ont pas de sens dans un contexte de messages/réponse.Comme
asyncore.dispatcher
,async_chat
définit un ensemble d’événements générés par une analyse de l’état des interfaces de connexion (socket en anglais) après un appel àselect()
. Une fois que la boucle de scrutation (polling en anglais) a été lancée, les méthodes des objetsasync_chat
sont appelées par le framework de traitement d’événements sans que le programmeur n’ait à le spécifier.Deux attributs de classe peuvent être modifiés, pour améliorer la performance, ou potentiellement pour économiser de la mémoire.
-
ac_in_buffer_size
¶ La taille du tampon d’entrées asynchrones (
4096
par défaut).
-
ac_out_buffer_size
¶ La taille du tampon de sorties asynchrones (
4096
par défaut).
Contrairement à
asyncore.dispatcher
,async_chat
permet de définir une queue FIFO de producteurs. Un producteur nécessite seulement une méthode,more()
, qui renvoie la donnée à transmettre au canal. Le producteur indique son épuisement (c.-à-d. qu’il ne contiens plus de données) en ne retournant avec sa méthodemore()
l’objet bytes vide. L’objetasync_chat
retire alors le producteur de la queue et commence à utiliser le producteur suivant, si il y en à un. Quand la queue de producteurs est vide, la méthodehandle_write()
ne fait rien. La méthodeset_terminator()
de l’objet du canal est utilisé pour décrire comment reconnaître la fin, ou la présence d’un point d’arrêt, dans in transmission entrante depuis le point d’accès distant.Pour construire une sous classe fonctionnelle de
async_chat
pour vos méthodes d’entréescollect_incoming_data()
etfound_terminator()
doivent gérer la donnée que le canal reçoit de manière asynchrone. Ces méthodes sont décrites ci-dessous.-
-
async_chat.
close_when_done
()¶ Pousse un
None
sur la pile de producteurs. Quand ce producteur est récupéré dans la queue, le canal est fermé.
-
async_chat.
collect_incoming_data
(data)¶ Appelé avec data contenant une quantité arbitraire de données. La méthode par défaut, qui doit être écrasée, lève une
NotImplementedError
.
-
async_chat.
discard_buffers
()¶ En cas d’urgence, cette méthode va supprimer tout donnée présente dans les tampons d’entrée et/ou de sortie dans la queue de producteurs.
-
async_chat.
found_terminator
()¶ Appelée quand le flux de donné corresponds à la condition de fin décrite par
set_terminator()
. La méthode par défaut, qui doit être écrasée, lève uneNotImplementedError
. Les données entrantes mise en tampon devraient être disponible via un attribut de l’instance.
-
async_chat.
get_terminator
()¶ Renvoie le terminateur courant pour le canal.
-
async_chat.
push
(data)¶ Pousse data sur la pile du canal pour assurer sa transmission. C’est tout ce dont on a besoin pour que le canal envoie des données sur le réseau. Cependant, il est possible d’utiliser vos propres producteurs dans des schémas plus complexes qui implémentent de la cryptographie et du chunking par exemple.
-
async_chat.
push_with_producer
(producer)¶ Prends un objet producteur l’ajoute à la queue de producteurs associée au canal. Quand tout les producteurs actuellement poussés ont été épuisé, le canal consomme les données de ce producteur en appelant sa méthode
more()
et envoie les données au point d’accès distant.
-
async_chat.
set_terminator
(term)¶ Définit le marqueur de fin que le canal doit reconnaître.
term
peut être n’importe lequel des trois types de valeurs, correspondant aux trois différentes manières de gérer les données entrantes.term
Description
string
Appellera
found_terminator()
quand la chaîne est trouvée dans le flux d’entréinteger
Appellera
found_terminator()
quand le nombre de caractère indiqué à été reçuNone
Le canal continue de collecter des informations indéfiniment
Notez que toute donnée située après le marqueur de fin sera accessible en lecture par le canal après que
found_terminator()
ai été appelé.
18.7.1. Exemple asynchat¶
L’exemple partiel suivant montre comment des requêtes HTTP peuvent être lues avec async_chat
. Un serveur web pourrait créer un objet http_request_handler
pour chaque connections lient entrantes. Notez que initialement, le marqueur de fin du canal est défini pour reconnaître les lignes vides à la fin des entêtes HTTP, et une option indique que les entêtes sont en train d’être lues.
Une fois que les entêtes ont été lues, si la requête est de type POST (ce qui indique que davantage de données sont présent dans dans le flux entrant) alors l’entête Content-Length:
est utilisé pour définir un marqueur de fin numérique pour lire la bonne quantité de donné depuis le canal.
La méthode handle_request()
est appelée une fois que toutes les données pertinentes ont été rassemblées, après avoir définit le marqueur de fin à None
pour s’assurer que toute données étrangères envoyées par le client web sont ignorées.
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()