Le fonctionnement global
La sélection de sockets s'inscrit dans un fonctionnement évènementiel, c'est à dire que tout se fait dans un seul thread et dans un seul et même processus. Elle présente une alternative puissante à l'utilisation des threads. Si vous avez lu le tutoriel de m@teo21 sur la SDL ou si vous connaissez, par exemple, l'API Windows, ce principe vous est déjà un peu familier

.
Avant, avec l'utilisation des threads sans la sélection de sockets, nous avions un schéma similaire à celui-ci :
Et maintenant en utilisant la sélection de socket, nous avons ce schéma :

Notez que les schémas ci-dessus sont des
grafcets :
- Chaque rectangle désigne donc une action (étape) repérée par un nombre unique.
- Chaque barre entre les actions désigne la condition pour que l'action suivante se réalise.
- Les étapes se déroulent dans l'ordre (l'étape 3 se déroule après l'étape 2 et ainsi de suite).
- On commence toujours par l'étape initiale (celle qui porte le numéro d'étape 0 et qui est encadré dans deux rectangles).
Dans le cas des threads, on crée une socket serveur, on liste les ports, puis pour chaque clients qui se connecte on crée un thread qui lui est approprié dans lequel la transmission entre le client et le serveur se déroulera.
Dans le cas de la sélection de sockets, on crée une socket serveur, on liste les ports, puis on initialise les descripteurs. Ensuite, on sélectionne la ou les socket(s) voulue(s) et pour chaque socket sélectionnée, on regarde dans quel état elle se trouve (y a t-il des données à lire ? à écrire ? etc.). Le tout ce fait dans un seul thread et dans un seul processus.
Notez que la sélection de sockets est bloquante pendant un temps que vous spécifiez ou non, c'est à dire que tant que l'état des descripteurs ne change pas ou tant que le temps donné n'est pas dépassé, la sélection reste bloquante. Si vous ne spécifiez pas de temps alors seul un changement d'état des descripteurs débloquera la sélection.
Qu'est ce qu'un descripteur de socket ?
Un descripteur de socket est tout simplement une variable (un entier) qui nous servira à manipuler la socket. L'état de cet entier peut nous permettre de connaître si des données ont été reçues ou envoyées sur la socket. Vous ne le savez peut être pas jusque là mais le type de variable
SOCKET est lui même un type de descripteur de socket. Le type
SOCKET n'est donc qu'un entier (
int), néanmoins on préfère utiliser le type
SOCKET pour mieux comprendre les choses et respecter les normes.
Qu'est ce qu'un ensemble ?
Un ensemble est un type de variable permettant de connaître l'état du descripteur de socket. Il en existe trois :
- L'ensemble de lecture readfds, il permet de savoir si le client a envoyé des données sur la socket sélectionnée. Un appel à recv ne sera donc pas bloquant
- L'ensemble de écriture writefds, il permet de savoir si le client a reçu les données sur la socket sélectionnée. Un appel à send ne sera donc pas bloquant
- L'ensemble d'exception exceptfds, il permet de gérer les exceptions mais nous ne nous en servirons pas dans ce chapitre.
Ce qu'il faut donc retenir
Vous pouvez choisir si la sélection de sockets sera bloquante ou non quand tel ou tel événement se produit en fonction des descripteurs que vous lui transmettez.
Prenons le cas ou vous spécifiez la sélection d'une socket client avec un descripteur en lecture seulement (on cherche à savoir si l'on peut lire des données sur la socket, si c'est le cas cela signifie que l'on a reçu des données sur cette socket

) et un temps limite de 50 ms : La sélection de la socket cliente est bloquante tant qu'elle ne reçoit pas de données jusqu'à ce que 50 ms se soit écoulé, après, la sélection rend la main (elle ne devient plus bloquante). La valeur qu'elle retourne spécifie l'évènement qui a mis fin au blocage (ici, le temps ou des données reçues peuvent mettre fin au blocage).