11.18 asyncore --- Gestionnaire de socket asynchrone

Ce module fournit l'infrastructure de base pour écrire des clients et serveurs de services de socket asynchrone.

Il n'y a que deux façons de faire en sorte qu'un programme sur un seul processeur puisse faire ``plus d'une chose à la fois.'' La programmation multi-threadée est la façon la plus simple et la plus répandue de le faire, mais il existe une autre technique très différente, qui vous laisse presque tous les avantages du multi-threading, sans utiliser de multiples threads. Ceci ne présente réellement d'avantage que si votre programme fait largement appel aux entrées-sorties. Si votre programme nécessite surtout de la CPU, alors des threads préemptifs programmés sont probablement ce dont vous avez besoin. Mais les serveurs de réseau sont rarement de gros consommateurs de CPU.

Si votre système d'exploitation prend en charge l'appel système select() dans sa bibliothèque d'entrée-sortie (et ils le font pratiquement tous), alors vous pouvez vous en servir pour jongler avec plusieurs canaux de communication en même temps; vous pourrez faire autre chose pendant que vos entrées-sorties se déroulent en arrière-plan. Bien que cette stratégie puisse sembler étrange et complexe, surtout au début, c'est à beaucoup de points de vue plus facile à comprendre et à contrôler que la programmation multi-threadée. Le module documenté ici résoud beaucoup des difficultés, et vous permet de construire des serveurs et des clients réseau sophistiqués et à haute performance en deux coups de cuiller à pot.

dispatcher()
La première classe que nous introduirons est la classe dispatcher. C'est un emballage fin autour d'un objet socket de bas niveau. Pour la rendre plus utile, elle possède quelques méthodes pour la gestion de ses événements. Sinon, elle peut être traitée comme un objet socket non bloquante normal.

L'interface directe entre la boucle select et l'objet socket sont les méthodes handle_read_event() et handle_write_event(). Elles sont appelées à chaque fois qu'un objet déclenche cet événement.

Le déclenchement de ces événements de bas niveau peut nous dire si certains événements de plus haut niveau se sont produits, en fonction de l'instant et de l'état de la connexion. Par exemple, si nous avons demandé à une socket de se connecter à un autre hôte, nous savons que la connexion a été établie quand la socket déclenche un événement d'écriture (arrivé là, vous savez que vous pouvez écrire dessus avec quelque chance de succès). Les événements de plus haut niveau sont:

Evénement Description 
handle_connect()Laisse supposer un événement d'écriture
handle_close()Laisse supposer un événement de lecture sans donnée disponible
handle_accept()Laisse supposer un événement de lecture sur une socket en écoute

L'ensemble des événements de niveau utilisateur est plus grand que ces bases. L'ensemble complet des méthodes qui peuvent être surchargées dans votre sous-classe est:

handle_read()
Appelée quand il y a de nouvelles données à lire depuis la socket.

handle_write()
Appelée quand il y a une tentative d'écrire des données sur l'objet. Souvent cette méthode implémentera le tamponnage nécessaire pour la performance. Par exemple:

def handle_write(self):
    envoye = self.send(self.buffer)
    self.buffer = self.buffer[envoye:]

handle_expt()
Appelée quand il y a des données hors bande (OOB) pour une connexion socket. Ceci n'arrivera pratiquement jamais, du fait que OOB est peu pris en charge et rarement utilisé.

handle_connect()
Appelée quand la socket établit effectivement une connexion. On peut s'en servir pour envoyer une bannière ``bienvenue'', ou quelque chose du même genre.

handle_close()
Appelée quand la socket est fermée.

handle_accept()
Appelée sur les sockets en écoute quand elles acceptent effectivement une nouvelle connexion.

readable()
A chaque temps de la boucle select(), l'ensemble des sockets est analysé, et cette méthode est appelée pour voir s'il y a un intérêt quelconque à lire. La méthode par défaut retourne simplement 1, indiquant que par défaut, tous les canaux seront intéressants.

writeable()
A chaque temps de la boucle select(), l'ensemble des sockets est analysé, et cette méthode est appelée pour voir s'il y a un intérêt quelconque à écrire. La méthode par défaut retourne simplement 1, indiquant que par défaut, tous les canaux seront intéressants.

En plus, il y a les méthodes basiques nécessaires pour construire et manipuler des ``canaux,'' qui sont ce que nous appelleront les connexions socket dans ce contexte. Notez que la plupart de celles-ci sont presque identiques à leur équivalent pour les sockets.

create_socket(famille, type)
Identique à la création d'une socket normale, et utilise les mêmes options pour la création. Reportez-vous à la documentation de socket pour des informations sur la création de sockets.

connect(adresse)
Comme pour les objets socket normaux, adresse est un tuple avec comme premier élément l'hôte auquel se connecter, et comme second le port.

send(donnees)
Envoie donnees sur la socket.

recv(taille_buffer)
Lit au plus taille_buffer depuis la socket.

listen([max_cx])
Se met en écoute de connexions établies sur la socket. L'argument max_cx spécifie le nombre maximum de connexions mises en file d'attente et doit valoir au moins un; la valeur maximum dépend du système (habituellement 5).

bind(adresse)
Lie la socket à l'adresse. La socket ne doit pas être déjà liée. (Le format de adresse dépend de la famille d'adresse - voir ci-dessus.)

accept()
Accepte une connexion. La socket doit être liée à une adresse et en écoute de connexions. La valeur de retour est une paire (conn, adresse)conn est un nouvel objet socket utilisable pour envoyer et recevoir des données sur la connexion, et adresse est l'adresse liée à la socket à l'autre extrémité de la connexion.

close()
Ferme la socket. Toutes les opérations ultérieures sur l'objet socket échoueront. L'extrémité distante ne recevra plus de données (après que les données en file d'attente auront été nettoyées). Les sockets sont automatiquement fermées quand elles passent au ramasse-miettes.


Sous-sections
  1. Exemple de client HTTP basique