Se connecter
Se connecter
Inscription
Mot de passe perdu
Connexion:
[Actualités]
Nvidia prévient d'une pénurie de GPU ce trimestre, avec une reprise début 2025
[Actualités]
Les Technos #469 : Un jour sans fin
[Actualités]
Test Farming Simulator 25 (PS5) - Des innovations intéressantes mais des perfor...
[Actualités]
Qualcomm souhaite réduire davantage les prix des PC Windows basés sur ARM
[Actualités]
Finalement, Google préparerait une nouvelle tablette mais la Pixel Tablet 2 ser...
[Actualités]
Windows 10 version 22H2 : erreur de mise à jour et de désinstallation
[Actualités]
OpenAI prépare désormais son propre navigateur
[Actualités]
WhatsApp bat Telegram : les transcriptions des messages vocaux arrivent pour tou...
[Actualités]
Unreal et Unreal Tournament désormais gratuits sur Internet Archive
[Actualités]
Windows 10 : Microsoft affiche des publicités en plein écran pour les PC équi...
[Articles]
Dungeons 4 - Nintendo Switch Edition
[Articles]
The Bridge Curse 2 : The Extrication
[Articles]
Farmagia
[Articles]
I*CHU: Chibi Edition
[Articles]
Farming Simulator 25
[Articles]
Goblin Slayer -Another Adventurer- Nightmare Feast
[Articles]
Deel lance des programmes en marque blanche et pour les revendeurs pour plus de ...
[Articles]
ESET Research : WolfsBane, nouvelle porte dérobée de cyber-espionnage Linux cr...
[Articles]
Devoteam présente son nouveau plan stratégique « AMPLIFY » avec un fort acce...
[Articles]
LEGO Horizon Adventures
Actualités
Lettre d'information
Proposer une actualité
Archives
Actualités
Articles
Programmation
Press Release
Matériel
Logiciels
Livres
Interviews
Derniers commentaires
Jeux Vidéos
XBox One
XBox 360
Wii U
PSP
PS4
PS3
PC
DS
GameCube
3DS
Forum
Derniers messages
Informatique
Fun
Divers
Logithèque
Blogs
Divers
A Propos
Annonceurs
Contact
Recherche
RSS
Editer un article
Titre
Mots Clés
Texte
[size=18] [b]Nom[/b] [/size] select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - Multiplexage d'E/S synchrones [size=18] [b]Résumé[/b] [/size] [b]#include
[/b] [b][/b] [b]#include
[/b] [b][/b] [b]#include
[/b] [b]int[/b] select(int [i]n[/i][b],[/b] fd_set *[i]readfds[/i][b],[/b] fd_set *[i]writefds[/i][b],[/b] fd_set *[i]exceptfds[/i][b],[/b] struct timeval *[i]utimeout[/i][b]);[/b] [b]int[/b] pselect(int [i]n[/i][b],[/b] fd_set *[i]readfds[/i][b],[/b] fd_set *[i]writefds[/i][b],[/b] fd_set *[i]exceptfds[/i][b],[/b] const struct timespec *[i]ntimeout[/i][b],[/b] sigset_t *[i]sigmask[/i][b]);[/b] [b]FD_CLR(int[/b] [i]fd[/i][b],[/b] fd_set *[i]set[/i][b]);[/b] [b][/b] [b]FD_ISSET(int[/b] [i]fd[/i][b],[/b] fd_set *[i]set[/i][b]);[/b] [b][/b] [b]FD_SET(int[/b] [i]fd[/i][b],[/b] fd_set *[i]set[/i][b]);[/b] [b][/b] [b]FD_ZERO(fd_set[/b] *[i]set[/i][b]);[/b] .fi [size=18] [b]Description[/b] [/size] [b]select[/b] (ou [b]pselect[/b]) est la fonction pivot de la plupart des programmes en C qui gèrent simultanément et de façon efficace plusieurs descripteurs de fichiers (ou sockets). Ses principaux arguments sont trois tableaux de descripteurs de fichiers : [i]readfds[/i], [i]writefds[/i], et [i]exceptfds[/i]. [b]select[/b] est généralement utilisé de façon à bloquer en attendant un "changement d'état" d'un ou plusieurs descripteurs de fichiers. Un "changement d'état" est signalé lorsque de nouveaux caractères sont mis à disposition sur le descripteur de fichier; [i]ou[/i] bien lorsque de l'espace devient disponible au niveau des tampons internes du noyau permettant de nouvelles écritures dans le descripteur de fichier, [i]ou[/i] bien lorsqu'un descripteur de fichier rencontre une erreur (dans le cas d'une socket ou d'un tube, une telle erreur est levée lorsque l'autre extrémité de la connexion est fermée). Pour résumer, [b]select[/b] surveille simplement de multiples descripteurs de fichiers, et constitue l'appel Unix standard pour réaliser cette tâche. Les tableaux de descripteurs de fichier sont appelés [i]ensembles[/i] de descripteurs de fichiers. Chaque ensemble est de type [b]fd_set[/b], et son contenu peut être modifié avec les macros [b]FD_CLR[/b], [b]FD_ISSET[/b], [b]FD_SET[/b], et [b]FD_ZERO[/b]. On commence généralement par utiliser [b]FD_ZERO[/b] sur un ensemble venant d'être créé. Ensuite, Les descripteurs de fichiers individuels qui vous intéressent peuvent être ajoutés un à un à l'aide de [b]FD_SET[/b]. [b]select[/b] modifie le contenu de ces ensembles selon les règles ci-dessous; Après un appel à [b]select[/b], vous pouvez vérifier si votre descripteur de fichier est toujours présent dans l'ensemble à l'aide de la macro [b]FD_ISSET[/b]. [b]FD_ISSET[/b] renvoie zéro si le descripteur de fichier est absent et une valeur non nulle sinon. [b]FD_CLR[/b] retire un descripteur de fichier de l'ensemble bien que je n'en vois pas l'utilité dans un programme propre. [size=18] [b]Arguments[/b] [/size] [table][row][col] [/col][col][i]readfds[/i] Cet ensemble est examiné afin de déterminer si des données sont disponibles en lecture à partir d'un de ses descripteurs de fichiers. Suite à un appel à [b]select[/b], [i]readfds[/i] ne contient plus aucun de ses descripteurs de fichiers à l'exception de ceux qui sont immédiatement disponibles pour une lecture via un appel [b]recv()[/b] (pour les sockets) ou [b]read()[/b] (pour les tubes, fichiers et sockets).[/col][/row][/table] [table][row][col] [/col][col][i]writefds[/i] Cet ensemble est examiné afin de déterminer s'il y a de l'espace afin d'écrire des données dans un de ses descripteurs de fichiers. Suite à un appel à [b]select[/b], [i]writefds[/i] ne contient plus aucun de ses descripteurs de fichiers à l'exception de ceux qui sont immédiatement disponibles pour une écriture via un appel à [b]send()[/b] (pour les sockets) ou [b]write()[/b] (pour les tubes, fichiers et sockets).[/col][/row][/table] [table][row][col] [/col][col][i]exceptfds[/i] Cet ensemble est examiné pour les exception ou les erreurs survenues sur les descripteurs de fichiers. Néanmoins, ceci n'est véritablement rien d'autre qu'une rumeur. [i]exceptfds[/i] est en fait utilisé afin de détecter l'occurence de données [i]hors-bande[/i] (Out Of Band). Les données hors bande sont celles qui sont envoyées sur une socket en utilisant le drapeau [b]MSG_OOB[/b], ainsi [i]exceptfds[/i] s'applique en réalité uniquement aux sockets. Voir [b]recv[/b](2) et [b]send[/b](2) à ce sujet. Suite à un appel à [b]select[/b], [i]exceptfds[/i] ne contient plus aucun de ses descripteurs de fichiers à l'exception de ceux qui sont disponibles pour une lecture de données hors-bande. Cependant, vous pouvez presque toujours lire uniquement un octet de données hors bande (à l'aide de [b]recv()[/b]), et l'écriture de données hors bande (avec [b]send[/b]) peut être effectuée à n'importe quel moment et n'est pas bloquante. Il n'y a donc pas de besoin d'un quatrième ensemble afin de vérifier si une socket est disponible pour une écriture de données hors bande.[/col][/row][/table] [table][row][col] [/col][col][i]n[/i] Il s'agit d'un entier valant un de plus que n'importe lequel des descripteurs de fichiers de tous les ensembles. En d'autres termes, lorsque vous ajoutez des descripteurs de fichiers à vos ensembles, vous devez déterminer la valeur entière maximale de tous ces derniers, puis ajouter un à cette valeur, et la passer en argument [i]n[/i] à [b]select[/b].[/col][/row][/table] [table][row][col] [/col][col][i]utimeout[/i][table][row][col] [/col][col] Il s'agit du temps le plus long que [b]select[/b] doit attendre avant de rendre la main, même si rien d'intéressant n'est arrivé. Si cette valeur est positionnée à [b]NULL[/b], alors, [b]select[/b] bloque indéfiniment dans l'attente d'un événement. [i]utimeout[/i] peut être positionné à zéro seconde, ce qui provoque le retour immédiat de [b]select[/b]. La structure [b]struct[/b] timeval est définie comme[/col][/row][/table] .nf struct timeval { long tv_sec; /* secondes */ long tv_usec; /* microsecondes */ }; .fi[/col][/row][/table] [table][row][col] [/col][col][i]ntimeout[/i][table][row][col] [/col][col] Cet argument a la même signification que [i]utimeout[/i] mais [b]struct[/b] timespec a une précision à la nanoseconde comme explicité ci dessous :[/col][/row][/table] .nf struct timespec { long tv_sec; /* secondes */ long tv_nsec; /* nanosecondes */ }; .fi[/col][/row][/table] [table][row][col] [/col][col][i]sigmask[/i] Cet argument renferme un ensemble de signaux non bloqués pendant un appel [b]pselect[/b] (voir [b]sigaddset[/b](3) et [b]sigprocmask[/b](2)). Il peut valoir NULL, et, dans ce cas, il ne modifie pas l'ensemble des signaux non bloqués à l'entrée et la sortie de la fonction. Il se comporte alors de façon identique à [b]select[/b]. [/col][/row][/table] [size=18] [b]Combinaison dÉvÉnements de signaux et de donnÉes[/b] [/size] [b]pselect[/b] doit être utilisé si vous attendez tout aussi bien un signal que des données d'un descripteur de fichier. Les programmes qui reçoivent les signaux comme des événements utilisent généralement le gestionnaire de signal uniquement pour lever un drapeau global. Le drapeau global indique que l'événement doit être traiter dans la boucle principale du programme. Un signal provoque l'arrêt de l'appel [b]select[/b] (ou [b]pselect[/b]) avec [b]errno[/b] positionnée à [b]EINTR[/b]. Ce comportement est essentiel afin que les signaux puissent être traités dans la boucle principale du programme, sinon [b]select[/b] bloquerait indéfiniment. Ceci étant, la boucle principale implante quelque part une condition vérifiant le drapeau global. et l'on doit donc se demander : que se passe t il si un signal est levé après la condition mais avant l'appel à [b]select[/b] ? La réponse est que [b]select[/b] bloquerait indéfiniment, même si un signal est en fait en attente. Cette "race condition" est résolue par l'appel [b]pselect[/b]. Cet appel peut être utilisé afin de débloquer des signaux qui ne sont pas censés être reçus si ce n'est durant l'appel à [b]pselect[/b]. Par exemple, disons que l'événement en question est la fin d'un processus fils. Avant le démarrage de la boucle principale, nous bloquerions [b]SIGCHLD[/b] en utilisant [b]sigprocmask[/b]. Notre appel [b]pselect[/b] débloquerait [b]SIGCHLD[/b] en utilisant le masque de signal initial. Le programme ressemblerait à ceci: .nf int child_events = 0; void child_sig_handler (int x) { child_events++; signal (SIGCHLD, child_sig_handler); } int main (int argc, char **argv) { sigset_t sigmask, orig_sigmask; sigemptyset (&sigmask); sigaddset (&sigmask, SIGCHLD); sigprocmask (SIG_BLOCK, &sigmask, &orig_sigmask); signal (SIGCHLD, child_sig_handler); for (;;) { /* main loop */ for (; child_events > 0; child_events--) { /* do event work here */ } r = pselect (n, &rd, &wr, &er, 0, &orig_sigmask); /* corps principal du programme */ } } .fi Remarquez que l'appel [b]pselect[/b] ci dessus peut être remplacé par : .nf sigprocmask (SIG_BLOCK, &orig_sigmask, 0); r = select (n, &rd, &wr, &er, 0); sigprocmask (SIG_BLOCK, &sigmask, 0); .fi mais il y a encore la possibilité qu'un signal arrive après le premier [b]sigprocmask[/b] et avant [b]select[/b]. si vous faites ceci, il est prudent de positionner tout au moins un timeout du durée finie de sorte que le processus ne bloque pas. Pour l'instant, la glibc fonctionne sans doute de cette manière, le noyau Linux n'ayant pas d'appel système natif [b]pselect[/b]. [size=18] [b]Pratique[/b] [/size] Quelle est donc la finalité de [b]select[/b]? Ne puis-je pas simplement lire et écrire dans les descripteurs chaque fois que je le souhaite ? L'objet de select est de surveiller de multiples descripteurs simultanément et d'endormir proprement le processus s'il n'y a pas d'activité. Il fait ceci tout en vous permettant de gérer de multiples tubes et sockets simultanément. Les programmeurs UNIX se retrouvent souvent dans une situation dans laquelle ils doivent gérer des E/S provenant de plus d'un descripteur de fichier et dans laquelle le flux de données est intermittent. Si vous deviez créer une séquence d'appels [b]read[/b] et [b]write[/b], vous vous retrouveriez potentiellement bloqué sur un de vos appels attendant pour lire ou écrire des données à partir/vers un descripteur de fichier, alors qu'un autre descripteur de fichier est inutilisé bien qu'il soit disponible pour lire/écrire des données. [b]select[/b] gère efficacement cette situation. Un exemple classique de [b]select[/b] vient de la page de manuel de [b]select[/b] : .nf #include
#include
#include
#include
int main(void) { fd_set rfds; struct timeval tv; int retval; /* Surveille stdin (fd 0) pour voir s'il a des données en entrée */ FD_ZERO(&rfds); FD_SET(0, &rfds); /* Attends jusqu'à 5 secondes. */ tv.tv_sec = 5; tv.tv_usec = 0; retval = select(1, &rfds, NULL, NULL, &tv); /* Ne pas se fier à la valeur de tv maintenant ! */ if (retval) printf("Des données sont disponibles maintenant "); /* FD_ISSET(0, &rfds) est alors vrai. */ else printf("Aucune donnée durant les cinq secondes. "); exit(0); } .fi [size=18] [b]Exemple de redirection de port[/b] [/size] Voici un exemple qui montre mieux l'utilité réelle de [b]select[/b]. Le code ci dessous consiste en un programme de "TCP forwarding" qui redirige un port TCP vers un autre. .nf #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int forward_port; #undef max #define max(x,y) ((x) > (y) ? (x) : (y)) static int listen_socket (int listen_port) { struct sockaddr_in a; int s; int yes; if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("socket"); return -1; } yes = 1; if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (yes)) < 0) { perror ("setsockopt"); close (s); return -1; } memset (&a, 0, sizeof (a)); a.sin_port = htons (listen_port); a.sin_family = AF_INET; if (bind (s, (struct sockaddr *) &a, sizeof (a)) < 0) { perror ("bind"); close (s); return -1; } printf ("accepting connections on port %d ", (int) listen_port); listen (s, 10); return s; } static int connect_socket (int connect_port, char *address) { struct sockaddr_in a; int s; if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("socket"); close (s); return -1; } memset (&a, 0, sizeof (a)); a.sin_port = htons (connect_port); a.sin_family = AF_INET; if (!inet_aton (address, (struct in_addr *) &a.sin_addr.s_addr)) { perror ("bad IP address format"); close (s); return -1; } if (connect (s, (struct sockaddr *) &a, sizeof (a)) < 0) { perror ("connect()"); shutdown (s, SHUT_RDWR); close (s); return -1; } return s; } #define SHUT_FD1 { if (fd1 >= 0) { shutdown (fd1, SHUT_RDWR); close (fd1); fd1 = -1; } } #define SHUT_FD2 { if (fd2 >= 0) { shutdown (fd2, SHUT_RDWR); close (fd2); fd2 = -1; } } #define BUF_SIZE 1024 int main (int argc, char **argv) { int h; int fd1 = -1, fd2 = -1; char buf1[BUF_SIZE], buf2[BUF_SIZE]; int buf1_avail, buf1_written; int buf2_avail, buf2_written; if (argc != 4) { fprintf (stderr, "Utilisation fwd
"); exit (1); } signal (SIGPIPE, SIG_IGN); forward_port = atoi (argv[2]); h = listen_socket (atoi (argv[1])); if (h < 0) exit (1); for (;;) { int r, n = 0; fd_set rd, wr, er; FD_ZERO (&rd); FD_ZERO (&wr); FD_ZERO (&er); FD_SET (h, &rd); n = max (n, h); if (fd1 > 0 && buf1_avail < BUF_SIZE) { FD_SET (fd1, &rd); n = max (n, fd1); } if (fd2 > 0 && buf2_avail < BUF_SIZE) { FD_SET (fd2, &rd); n = max (n, fd2); } if (fd1 > 0 && buf2_avail - buf2_written > 0) { FD_SET (fd1, &wr); n = max (n, fd1); } if (fd2 > 0 && buf1_avail - buf1_written > 0) { FD_SET (fd2, &wr); n = max (n, fd2); } if (fd1 > 0) { FD_SET (fd1, &er); n = max (n, fd1); } if (fd2 > 0) { FD_SET (fd2, &er); n = max (n, fd2); } r = select (n + 1, &rd, &wr, &er, NULL); if (r == -1 && errno == EINTR) continue; if (r < 0) { perror ("select()"); exit (1); } if (FD_ISSET (h, &rd)) { unsigned int l; struct sockaddr_in client_address; memset (&client_address, 0, l = sizeof (client_address)); r = accept (h, (struct sockaddr *) &client_address, &l); if (r < 0) { perror ("accept()"); } else { SHUT_FD1; SHUT_FD2; buf1_avail = buf1_written = 0; buf2_avail = buf2_written = 0; fd1 = r; fd2 = connect_socket (forward_port, argv[3]); if (fd2 < 0) { SHUT_FD1; } else printf ("connexion de %s ", inet_ntoa (client_address.sin_addr)); } } /* NB: lecture des données hors bande avant les lectures normales */ if (fd1 > 0) if (FD_ISSET (fd1, &er)) { char c; errno = 0; r = recv (fd1, &c, 1, MSG_OOB); if (r < 1) { SHUT_FD1; } else send (fd2, &c, 1, MSG_OOB); } if (fd2 > 0) if (FD_ISSET (fd2, &er)) { char c; errno = 0; r = recv (fd2, &c, 1, MSG_OOB); if (r < 1) { SHUT_FD1; } else send (fd1, &c, 1, MSG_OOB); } if (fd1 > 0) if (FD_ISSET (fd1, &rd)) { r = read (fd1, buf1 + buf1_avail, BUF_SIZE - buf1_avail); if (r < 1) { SHUT_FD1; } else buf1_avail += r; } if (fd2 > 0) if (FD_ISSET (fd2, &rd)) { r = read (fd2, buf2 + buf2_avail, BUF_SIZE - buf2_avail); if (r < 1) { SHUT_FD2; } else buf2_avail += r; } if (fd1 > 0) if (FD_ISSET (fd1, &wr)) { r = write (fd1, buf2 + buf2_written, buf2_avail - buf2_written); if (r < 1) { SHUT_FD1; } else buf2_written += r; } if (fd2 > 0) if (FD_ISSET (fd2, &wr)) { r = write (fd2, buf1 + buf1_written, buf1_avail - buf1_written); if (r < 1) { SHUT_FD2; } else buf1_written += r; } /* Vérifie si l'écriture de données a provoqué la lecture de données*/ if (buf1_written == buf1_avail) buf1_written = buf1_avail = 0; if (buf2_written == buf2_avail) buf2_written = buf2_avail = 0; /* une extrémité a fermé la connexion, continue d'écrire vers l'autre extrémité jusqu'à ce que ce soit vide*/ if (fd1 < 0 && buf1_avail - buf1_written == 0) { SHUT_FD2; } if (fd2 < 0 && buf2_avail - buf2_written == 0) { SHUT_FD1; } } return 0; } .fi Le programme ci dessus redirige correctement la plupart des types de connexions TCP y compris les signaux de données hors bande OOB transmis par les serveurs [b]telnet[/b]. Il gère le problème épineux des flux de données bidirectionnels simultanés. Vous pourriez penser qu'il est plus efficace d'utiliser un appel [b]fork()[/b] et de dédier une tâche à chaque flux. Cela devient alors plus délicat que vous ne l'imaginez. Une autre idée est de configurer les E/S comme non bloquantes en utilisant un appel [b]ioctl()[/b]. Cela pose également problème parce que vous finissez par avoir des timeouts inefficaces. Le programme ne gère pas plus d'une connexion à la fois bien qu'il soit aisément extensible à une telle fonctionnalité en utilisant une liste chainée de buffers - un pour chaque connexion. Pour l'instant, de nouvelles connexions provoquent l'abandon de la connexion courante. [size=18] [b]RÈgles de select[/b] [/size] De nombreuses personnes qui essaient d'utiliser [b]select[/b] obtiennent un comportement difficile à comprendre et produisent des résultats non portables ou des effets de bord. Par exemple, le programme ci dessus est écrit avec précaution afin de ne bloquer nulle part, même s'il ne positionne pas du tout ses descripteurs de fichiers en mode non bloquant (voir [b]ioctl[/b](2)). Il est facile d'introduire des erreurs subtiles qui annuleraient l'avantage de l'utilisation de [b]select[/b], aussi, vais je présenter une liste de points essentiels à contrôler lors de l'utilisation de l'appel [b]select[/b]. [table][row][col] [/col][col][b]1.[/b] Vous devriez toujours essayer d'utiliser [b]select[/b] sans timeout. Votre programme ne devrait rien avoir à faire s'il n'y a pas de données disponibles. Le code dépendant de timeouts n'est en général pas portable et difficile à déboguer.[/col][/row][/table] [table][row][col] [/col][col][b]2.[/b] La valeur [i]n[/i] doit être calculée correctement pour des raisons d'efficacité comme expliqué plus haut.[/col][/row][/table] [table][row][col] [/col][col][b]3.[/b] Aucun descripteur de fichier ne doit être ajouté à un quelconque ensemble si vous ne projetez pas de vérifier son état après un appel à [b]select[/b], et de réagir de façon adéquate. Voir la règle suivante.[/col][/row][/table] [table][row][col] [/col][col][b]4.[/b] Après qu'un appel [b]select[/b] a rendu la main, tous les descripteurs de fichiers de tous les ensembles [i]doivent[/i] être vérifiés. Tout descripteur de fichier disponible pour l'écriture [i]doit[/i] être alimenté, et tout descripteur de fichier disponible pour la lecture [i]doit[/i] être lu, etc.[/col][/row][/table] [table][row][col] [/col][col][b]5.[/b] Les fonctions [b]read()[/b], [b]recv()[/b], [b]write()[/b], et [b]send()[/b] ne lisent ou n'écrivent [b]pas[/b] forcément la quantité totale de données spécifiée. Si elles lisent/écrivent la quantité totale, c'est parce que vous avez une faible charge de trafic et un flux rapide. Ce n'est pas toujours le cas. Vous devriez gérer la cas où vos fonctions traitent seulement l'envoi ou la réception d'un unique octet.[/col][/row][/table] [table][row][col] [/col][col][b]6.[/b] Ne lisez/N'écrivez jamais seulement quelques octets à la fois à moins que vous ne soyez absolument sûr de n'avoir qu'une faible quantité de données à traiter. Il est parfaitement inefficace de ne pas lire/écrire autant de données que vous pouvez en stocker à chaque fois. Les tampons de l'exemple ci dessus font 1024 octets bien qu'ils aient facilement pu être rendus aussi importants que la taille de paquet maximale sur votre réseau local.[/col][/row][/table] [table][row][col] [/col][col][b]7.[/b] Les fonctions [b]read()[/b], [b]recv()[/b], [b]write()[/b], et [b]send()[/b] tout comme l'appel [b]select()[/b] peuvent renvoyer -1 avec errno positionné à [b]EINTR[/b] ou [b]EAGAIN[/b] ([b]EWOULDBLOCK[/b]) ce qui ne relève pas de l'erreur. Ces résultats doivent être correctement gérés (cela n'est pas fait correctement ci dessus.) Si votre programme n'est pas censé recevoir de signal, alors, il est hautement improbable que vous obteniez [b]EINTR[/b]. Si votre programme n'a pas configuré les E/S en mode non bloquant, vous n'obtiendrez pas de [b]EAGAIN[/b]. Néanmoins, vous devriez tout de même gérer ces erreurs dans un soucis de complétude.[/col][/row][/table] [table][row][col] [/col][col][b]8.[/b] N'appelez jamais [b]read()[/b], [b]recv()[/b], [b]write()[/b], ou [b]send()[/b] avec un buffer de taille nulle[/col][/row][/table] [table][row][col] [/col][col][b]9.[/b] A l'exception des cas indiqués en [b]7.[/b], les fonctions [b]read()[/b], [b]recv()[/b], [b]write()[/b], et [b]send()[/b] n'ont jamais une valeur de retour inférieure à 1 sauf si une erreur est survenue. Par exemple, un [b]read()[/b] sur un tube dont l'extrémité est morte renvoie zéro (de même qu'une erreur de fin de fichier), [i]mais[/i] ne renvoie zéro qu'une seule fois. Dans le cas où l'une de ces fonctions renvoie 0 ou -1, vous ne devriez [i]pas[/i] utiliser ce descripteur à nouveau. Dans l'exemple ci dessus, je ferme le descripteur immédiatement, et ensuite, je le positionne à -1 afin qu'il ne soit pas inclus dans un ensemble.[/col][/row][/table] [table][row][col] [/col][col][b]10.[/b] La valeur de timeout doit être initialisée à chaque nouvel appel à [b]select[/b], puisque des systèmes d'exploitation modifient la structure. Cependant, [b]pselect[/b] ne modifie pas sa structure de timeout.[/col][/row][/table] [table][row][col] [/col][col][b]11.[/b] J'ai entendu que le niveau socket Windows ne traite pas correctement les données hors bande (OOB). Il ne gère pas non plus les appels [b]select[/b] lorsqu'aucun descripteur de fichier n'est positionné. N'avoir aucun descripteur de fichier positionné est un moyen utile afin d'endormir le processus avec une précision inférieure à la seconde en utilisant le timeout. (Voir plus loin.) [/col][/row][/table] [size=18] [b]Émulation de usleep[/b] [/size] Sur les systèmes qui ne possèdent pas la fonction [b]usleep[/b], vous pouvez appeler [b]select[/b] avec un timeout à valeur finie et sans descripteur de fichier de la façon suivante : .nf struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 200000; /* 0.2 secondes */ select (0, NULL, NULL, NULL, &tv); .fi Le fonctionnement n'est cependant garanti que sur les systèmes Unix. [size=18] [b]Valeur renvoyée[/b] [/size] En cas de succès, [b]select[/b] renvoie le nombre total de descripteurs de fichiers encore présents dans les ensembles de descripteurs de fichiers. En cas de timeout échu, alors les descripteurs de fichiers devraient tous être vides (mais peuvent ne pas l'être sur certains systèmes). par contre, la valeur renvoyée est clairement zéro. Une valeur de retour égale à -1 indique une erreur, [b]errno[/b] est alors positionné de façon adéquate. En cas d'erreur, les ensembles renvoyés et le contenu de la structure de timeout sont indéfinis et ne devraient pas être exploités. [b]pselect[/b] ne modifie cependant jamais [i]ntimeout[/i]. [size=18] [b]Erreurs[/b] [/size] [table][row][col] [/col][col][b]EBADF[/b] Un ensemble contenait un descripteur de fichier invalide. Cette erreur se produit fréquemment lorsque l'on ajoute à un ensemble un descripteur de fichier qui a déjà été fermé avec un appel [b]close[/b], ou lorsque ce descripteur de fichier a déjà accusé une erreur. Ainsi, devriez vous cesser d'ajouter aux ensembles tout descripteur de fichier qui renvoie une erreur de lecture ou d'écriture.[/col][/row][/table] [table][row][col] [/col][col][b]EINTR[/b] Un signal interrompant l'appel a été intercepté, par exemple un signal [b]SIGINT[/b] ou [b]SIGCHLD[/b] etc. Dans un tel cas, vous devriez rétablir vos ensembles de descripteurs de fichiers et réessayer.[/col][/row][/table] [table][row][col] [/col][col][b]EINVAL[/b] Est renvoyé si [i]n[/i] a une valeur négative.[/col][/row][/table] [table][row][col] [/col][col][b]ENOMEM[/b] Echec d'allocation de mémoire interne. [/col][/row][/table] [size=18] [b]Notes[/b] [/size] De façon générale, tous les systèmes d'exploitation qui gèrent les sockets, implantent également [b]select[/b]. Certaines personnes considèrent [b]select[/b] comme une fonction ésotérique et rarement utilisée. En fait, de nombreux types de programmes deviennent extrêmement compliqués sans cette fonction. [b]select[/b] peut être utilisé pour résoudre de façon portable et efficace de nombreux problèmes que des programmeurs naïfs essaient de résoudre avec des threads, des forks, des IPCs, des signaux, des mémoires partagées et d'autres méthodes peu élégantes. [b]pselect[/b] est une fonction plus récente qui est moins répandue. L'appel-système [b]poll (2)[/b] a les mêmes fonctionnalités que [b]select[/b], avec un comportement un peu moins subtil.Il est moins portable que [b]select[/b]. [size=18] [b]Conformité[/b] [/size] BSD4.4(la fonction [b]select[/b] est tout d'abord apparue dans BSD4.2). Généralement portable de/vers des systèmes non BSD possédant un équivalent au niveau socket BSD (y compris les variantes système V). Néanmoins, notez bien que la variante système V positionne typiquement la variable timeout avant de rendre la main alors que la variante BSD ne le fait pas. La fonction [b]pselect[/b] est définie dans le standard IEEE 1003.1g-2000 (POSIX.1g). On la trouve dans la glibc 2.1 et les versions suivantes. La Glibc 2.0 possède une fonction portant ce nom mais qui n'a pas de pas de paramètre [i]sigmask[/i] . [size=18] [b]Voir aussi[/b] [/size] [b]accept (2),[/b] [b]connect (2),[/b] [b]ioctl (2),[/b] [b]poll (2),[/b] [b]read (2),[/b] [b]recv (2),[/b] [b]select (2),[/b] [b]send (2),[/b] [b]sigaddset (3),[/b] [b]sigdelset (3),[/b] [b]sigemptyset (3),[/b] [b]sigfillset (3),[/b] [b]sigismember (3),[/b] [b]sigprocmask (2),[/b] [b]write (2)[/b] [size=18] [b]Auteurs[/b] [/size] Cette page de manuel a été rédigée par Paul Sheer. [size=18] [b]Traduction[/b] [/size] Stéphan Rafin, 2002 [b][/b] Christophe Blaess, 2003.
Fichier
Forum
-
Derniers messages
Bavardages
Aujourd'hui, je rénove ou je construis ^^
Software
problème sur windows 10
Réseaux et Télécom
Administrateur Réseau - Cisco
Réseaux et Télécom
Problème wifi (POE)
Software
Postfix - Need help
Bavardages
Oh râge oh désespoir !
Programmation
Enregistrement client et envoi mail
Software
SÉCURITÉ MACBOOK
Hardware
conseil matos réseau?
Hardware
nVidia Shield Android TV
Actualités
-
Archives
Matériel
Nvidia prévient d'une pénurie de GPU ce trimestre, avec une reprise début 2025
Les Technos
Les Technos #469 : Un jour sans fin
Jeux Vidéos
Test Farming Simulator 25 (PS5) - Des innovations intéressantes mais des performances à revoir
Matériel
Qualcomm souhaite réduire davantage les prix des PC Windows basés sur ARM
Tablettes
Finalement, Google préparerait une nouvelle tablette mais la Pixel Tablet 2 serait abandonnée
Ada
CSS
Cobol
CPP
HTML
Fortran
Java
JavaScript
Pascal
Perl
PHP
Python
SQL
VB
XML
Anon URL
DailyMotion
eBay
Flickr
FLV
Google Video
Google Maps
Metacafe
MP3
SeeqPod
Veoh
Yahoo Video
YouTube
6px
8px
10px
12px
14px
16px
18px
Informaticien.be
- © 2002-2024
Akretio
SPRL - Generated via
Kelare
The Akretio Network:
Akretio
-
Freedelity
-
KelCommerce
-
Votre publicité sur informaticien.be ?