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.
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:
def handle_write(self):
envoye = self.send(self.buffer)
self.buffer = self.buffer[envoye:]
1, indiquant que par défaut, tous les canaux seront intéressants.
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.
(conn, adresse) où 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.