Provided by: manpages-fr-dev_3.27fr1.4-1_all bug

NOM

       select,  pselect,  FD_CLR,  FD_ISSET,  FD_SET,  FD_ZERO  - Multiplexage
       d'entrees-sorties synchrones

SYNOPSIS

       /* D'apres POSIX.1-2001 */
       #include <sys/select.h>

       /* D'apres les standards precedents */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *utimeout);

       void FD_CLR(int fd, fd_set *set);
       int  FD_ISSET(int fd, fd_set *set);
       void FD_SET(int fd, fd_set *set);
       void FD_ZERO(fd_set *set);

       #include <sys/select.h>

       int pselect(int nfds, fd_set *readfds, fd_set *writefds,
                   fd_set *exceptfds, const struct timespec *ntimeout,
                   const sigset_t *sigmask);

   Exigences de macros de test de fonctionnalites  pour  la  glibc  (consultez
   feature_test_macros(7)) :

       pselect() : _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600

DESCRIPTION

       select()  (ou  pselect())  est  utilise  pour  superviser  efficacement
       plusieurs descripteurs de fichiers pour verifier si  l'un  d'entre  eux
       est  ou devient << pret >> ; c'est-a-dire savoir si des entrees-sorties
       deviennent possibles ou  si  une  <<  condition  exceptionnelle >>  est
       survenue sur l'un des descripteurs.

       Ses parametres principaux sont trois << ensembles >> de descripteurs de
       fichiers : readfds, writefds et exceptfds. Chaque ensemble est de  type
       fd_set,  et  son  contenu  peut etre manipule avec les macros FD_CLR(),
       FD_ISSET(), FD_SET(), et FD_ZERO(). Un  ensemble  nouvellement  declare
       doit  d'abord  etre  efface en utilisant FD_ZERO(). select() modifie le
       contenu de ces ensembles selon les regles ci-dessous. Apres un appel  a
       select(),  vous  pouvez  verifier  si  un  descripteur  de  fichier est
       toujours present dans l'ensemble  a  l'aide  de  la  macro  FD_ISSET().
       FD_ISSET()  renvoie  une  valeur non nulle si un descripteur de fichier
       indique est present dans  un  ensemble  et  zero  s'il  ne  l'est  pas.
       FD_CLR() retire un descripteur de fichier d'un ensemble.

   Arguments
       readfds
              Cet  ensemble est examine afin de determiner si des donnees sont
              disponibles en lecture a partir  d'un  de  ses  descripteurs  de
              fichier.  Suite  a un appel a select(), readfds ne contient plus
              aucun de ses descripteurs de fichiers a l'exception de ceux  qui
              sont immediatement disponibles pour une lecture.

       writefds
              Cet ensemble est examine afin de determiner s'il y a de l'espace
              afin d'ecrire  des  donnees  dans  un  de  ses  descripteurs  de
              fichier.  Suite a un appel a select(), writefds ne contient plus
              aucun de ses descripteurs de fichiers a l'exception de ceux  qui
              sont immediatement disponibles pour une ecriture.

       exceptfds
              Cet    ensemble    est    examine    pour    des   << conditions
              exceptionnelles >>.   En   pratique,   seule    une    condition
              exceptionnelle   est  courante :  la  disponibilite  de  donnees
              hors-bande (OOB : Out Of Band) en lecture sur  une  socket  TCP.
              Consultez  recv(2),  send(2)  et tcp(7) pour plus de details sur
              les donnees hors bande. Un autre cas moins courant  dans  lequel
              select(2) indique une condition exceptionnelle survient avec des
              pseudoterminaux en mode paquet ; consultez tty_ioctl(4).)  Suite
              a  un  appel a select(), exceptfds ne contient plus aucun de ses
              descripteurs de fichier a l'exception de ceux pour lesquels  une
              condition exceptionnelle est survenue.

       nfds   Il s'agit d'un entier valant un de plus que n'importe lequel des
              descripteurs de fichier  de  tous  les  ensembles.  En  d'autres
              termes,  lorsque  vous  ajoutez  des  descripteurs  de fichier a
              chacun des ensembles, vous devez determiner  la  valeur  entiere
              maximale  de  tous ces derniers, puis ajouter un a cette valeur,
              et la passer comme parametre nfds.

       utimeout
              Il s'agit du temps le plus long que select()  pourrait  attendre
              avant  de  rendre  la  main,  meme  si  rien d'interessant n'est
              arrive. Si cette valeur est positionnee a NULL, alors,  select()
              bloque  indefiniment dans l'attente qu'un descripteur de fichier
              devienne pret. utimeout peut etre positionne a zero seconde,  ce
              qui  provoque le retour immediat de select(), en indiquant quels
              descripteurs de fichiers etaient prets au moment de l'appel.  La
              structure struct timeval est definie comme :

                  struct timeval {
                      time_t tv_sec;    /* secondes */
                      long tv_usec;     /* microsecondes */
                  };

       ntimeout
              Ce  parametre de pselect() a la meme signification que utimeout,
              mais struct timespec a une  precision  a  la  nanoseconde  comme
              explicite ci-dessous :

                  struct timespec {
                      long tv_sec;    /* secondes */
                      long tv_nsec;   /* nanosecondes */
                  };

       sigmask
              Cet  argument  renferme un ensemble de signaux que le noyau doit
              debloquer (c'est-a-dire supprimer du masque de signaux du thread
              appelant)  pendant  que  l'appelant  est  bloque  par  pselect()
              (consultez sigaddset(3) et sigprocmask(2)). Il peut valoir  NULL
              et,  dans  ce  cas, il ne modifie pas l'ensemble des signaux non
              bloques a l'entree et la sortie de la  fonction.  Dans  ce  cas,
              pselect() se comporte alors de facon identique a select().

   Combinaison d''ev'enements de signaux et de donn'ees
       pselect()  est utile si vous attendez un signal ou qu'un descripteur de
       fichier deviennent pret pour des entrees-sorties.  Les  programmes  qui
       recoivent  des signaux utilisent generalement le gestionnaire de signal
       uniquement pour lever un drapeau global. Le drapeau global indique  que
       l'evenement doit etre traite dans la boucle principale du programme. Un
       signal provoque l'arret de l'appel select() (ou pselect())  avec  errno
       positionnee a EINTR. Ce comportement est essentiel afin que les signaux
       puissent etre traites dans la boucle  principale  du  programme,  sinon
       select()  bloquerait  indefiniment.  Ceci  etant,  la boucle principale
       implante quelque part une condition verifiant  le  drapeau  global,  et
       l'on  doit  donc  se demander : que se passe-t-il si un signal est leve
       apres la condition mais avant l'appel a select() ? La reponse  est  que
       select()  bloquerait  indefiniment,  meme  si  un signal est en fait en
       attente. Cette "race condition" est resolue par l'appel pselect().  Cet
       appel  peut etre utilise afin de definir le masque des signaux qui sont
       censes etre recus que durant l'appel a pselect(). Par  exemple,  disons
       que  l'evenement  en  question est la fin d'un processus fils. Avant le
       demarrage  de  la  boucle  principale,  nous  bloquerions  SIGCHLD   en
       utilisant sigprocmask(2). Notre appel pselect() debloquerait SIGCHLD en
       utilisant le masque de  signaux  vide.  Le  programme  ressemblerait  a
       ceci :

       static volatile sig_atomic_t got_SIGCHLD = 0;

       static void
       child_sig_handler(int sig)
       {
           got_SIGCHLD = 1;
       }

       int
       main(int argc, char *argv[])
       {
           sigset_t sigmask, empty_mask;
           struct sigaction sa;
           fd_set readfds, writefds, exceptfds;
           int r;

           sigemptyset(&sigmask);
           sigaddset(&sigmask, SIGCHLD);
           if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1) {
               perror("sigprocmask");
               exit(EXIT_FAILURE);
           }

           sa.sa_flags = 0;
           sa.sa_handler = child_sig_handler;
           sigemptyset(&sa.sa_mask);
           if (sigaction(SIGCHLD, &sa, NULL) == -1) {
               perror("sigaction");
               exit(EXIT_FAILURE);
           }

           sigemptyset(&empty_mask);

           for (;;) {          /* main loop */
               /* Initialiser readfds, writefds et exceptfds
                  avant l'appel a pselect(). (Code omis.) */

               r = pselect(nfds, &readfds, &writefds, &exceptfds,
                           NULL, &empty_mask);
               if (r == -1 && errno != EINTR) {
                   /* Gerer les erreurs */
               }

               if (got_SIGCHLD) {
                   got_SIGCHLD = 0;

                   /* Gerer les evenements signales ici; e.g., wait() pour
                      que tous les fils se terminent. (Code omis.) */
               }

               /* corps principal du programme */
           }
       }

   Pratique
       Quelle  est  donc  la  finalite de select() ? Ne peut on pas simplement
       lire et ecrire dans les descripteurs chaque fois  qu'on  le  souhaite ?
       L'objet  de  select()  est  de  surveiller  de  multiples  descripteurs
       simultanement et d'endormir proprement le  processus  s'il  n'y  a  pas
       d'activite.  Les  programmeurs  UNIX  se  retrouvent  souvent  dans une
       situation dans laquelle ils doivent gerer des entrees-sorties provenant
       de plus d'un descripteur de fichier et dans laquelle le flux de donnees
       est intermittent. Si vous deviez creer une sequence d'appels read(2) et
       write(2),  vous  vous retrouveriez potentiellement bloque sur un de vos
       appels attendant pour lire ou  ecrire  des  donnees  a  partir/vers  un
       descripteur  de  fichier,  alors qu'un autre descripteur de fichier est
       inutilise bien qu'il soit pret pour des entrees-sorties. select()  gere
       efficacement cette situation.

   R`egles de select
       De  nombreuses personnes qui essaient d'utiliser select() obtiennent un
       comportement difficile a comprendre et  produisent  des  resultats  non
       portables  ou  des  effets de bord. Par exemple, le programme ci-dessus
       est ecrit avec precaution afin de ne bloquer nulle part, meme  s'il  ne
       positionne  pas ses descripteurs de fichier en mode non bloquant.Il est
       facile d'introduire des erreurs subtiles qui annuleraient l'avantage de
       l'utilisation  de select(), aussi, voici une liste de points essentiels
       a controler lors de l'utilisation de select().

       1.  Vous devriez toujours essayer  d'utiliser  select()  sans  timeout.
           Votre  programme  ne  devrait  rien avoir a faire s'il n'y a pas de
           donnees disponibles. Le code dependant de timeouts n'est en general
           pas portable et difficile a deboguer.

       2.  La  valeur  nfds  doit  etre calculee correctement pour des raisons
           d'efficacite comme explique plus haut.

       3.  Aucun descripteur de fichier ne doit etre ajoute  a  un  quelconque
           ensemble  si  vous  ne  projetez  pas de verifier son etat apres un
           appel a select(), et de reagir de facon  adequate.  Voir  la  regle
           suivante.

       4.  Apres  le retour de select(), tous les descripteurs de fichier dans
           tous les ensembles devraient etre testes  pour  savoir  s'ils  sont
           prets.

       5.  Les  fonctions  read(2),  recv(2), write(2) et send(2) ne lisent ou
           n'ecrivent pas forcement la quantite totale de  donnees  specifiee.
           Si  elles  lisent/ecrivent la quantite 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  gerer  le  cas  ou vos fonctions
           traitent seulement l'envoi ou la reception d'un unique octet.

       6.  Ne lisez/n'ecrivez jamais seulement quelques octets  a  la  fois  a
           moins  que  vous  ne  soyez absolument sur de n'avoir qu'une faible
           quantite de donnees a traiter. Il est parfaitement inefficace de ne
           pas  lire/ecrire  autant  de  donnees  que vous pouvez en stocker a
           chaque fois. Les tampons de l'exemple ci-dessous font  1024  octets
           bien qu'ils aient facilement pu etre rendus plus grands.

       7.  Les  fonctions  read(2),  recv(2),  write(2)  et send(2) tout comme
           l'appel select() peuvent renvoyer -1 avec errno positionne a  EINTR
           ou  EAGAIN  (EWOULDBLOCK)  ce  qui  ne releve pas d'une erreur. Ces
           resultats doivent etre correctement  geres  (cela  n'est  pas  fait
           correctement   ci-dessus).  Si  votre  programme  n'est  pas  cense
           recevoir de signal, alors, il est  hautement  improbable  que  vous
           obteniez   EINTR.   Si   votre  programme  n'a  pas  configure  les
           entrees-sorties en mode non  bloquant,  vous  n'obtiendrez  pas  de
           EAGAIN.

       8.  N'appelez  jamais  read(2),  recv(2),  write(2)  ou send(2) avec un
           tampon de taille nulle.

       9.  Si l'une des fonctions read(2), recv(2), write(2) et send(2) echoue
           avec  une  erreur autre que celles indiquees en 7., ou si l'une des
           fonctions d'entree renvoie 0, indiquant une fin de fichier, vous ne
           devriez  pas  utiliser  ce  descripteur  a  nouveau pour un appel a
           select().   Dans   l'exemple   ci-dessous,   le   descripteur   est
           immediatement  ferme  et  ensuite est positionne a -1 afin qu'il ne
           soit pas inclus dans un ensemble.

       10. La valeur de timeout doit etre initialisee a chaque nouvel appel  a
           select(),   puisque   des   systemes  d'exploitation  modifient  la
           structure. Cependant, pselect() ne  modifie  pas  sa  structure  de
           timeout.

       11. Comme  select()  modifie ses ensembles de descripteurs de fichiers,
           si l'appel est effectue dans une boucle alors les ensembles doivent
           etre reinitialises avant chaque appel.

   'Emulation de usleep
       Sur  les  systemes  qui  ne  possedent  pas la fonction usleep(3), vous
       pouvez appeler  select()  avec  un  timeout  a  valeur  finie  et  sans
       descripteur de fichier de la facon suivante :

           struct timeval tv;
           tv.tv_sec = 0;
           tv.tv_usec = 200000;  /* 0.2 secondes */
           select(0, NULL, NULL, NULL, &tv);

       Le fonctionnement n'est cependant garanti que sur les systemes Unix.

VALEUR RENVOY'EE

       En  cas  de succes, select() renvoie le nombre total de descripteurs de
       fichiers encore presents dans les ensembles de descripteurs de fichier.

       En cas de timeout echu, alors les  descripteurs  de  fichier  devraient
       tous etre vides (mais peuvent ne pas l'etre sur certains systemes). Par
       contre, la valeur renvoyee est zero.

       Une valeur de retour egale a -1 indique une  erreur,  errno  est  alors
       positionne de facon adequate. En cas d'erreur, le contenu des ensembles
       renvoyes et le contenu de la structure de timeout sont indefinis et  ne
       devraient  pas  etre  exploites.  pselect() ne modifie cependant jamais
       ntimeout.

NOTES

       De facon generale, tous les  systemes  d'exploitation  qui  gerent  les
       sockets  proposent  egalement select(). select() peut etre utilise pour
       resoudre de facon portable et efficace de nombreux  problemes  que  des
       programmeurs  naifs  essaient  de resoudre avec des threads, des forks,
       des IPC, des signaux, des memoires partagees et d'autres  methodes  peu
       elegantes.

       L'appel  systeme poll(2) a les memes fonctionnalites que select(), tout
       en  etant  legerement  plus  efficace  quand  il  doit  surveiller  des
       ensembles  de  descripteurs creux. Il est disponible sur la plupart des
       systemes de nos jours, mais etait  historiquement  moins  portable  que
       select().

       L'API  epoll(7)  specifique a Linux fournit une interface plus efficace
       que select(2) et poll(2) lorsque l'on  surveille  un  grand  nombre  de
       descripteurs de fichier.

EXEMPLE

       Voici un exemple qui montre mieux l'utilite reelle de select(). Le code
       ci-dessous  consiste  en  un  programme  de  << TCP  forwarding >>  qui
       redirige un port TCP vers un autre.

       #include <stdlib.h>
       #include <stdio.h>
       #include <unistd.h>
       #include <sys/time.h>
       #include <sys/types.h>
       #include <string.h>
       #include <signal.h>
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>
       #include <errno.h>

       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)) == -1) {
               perror("socket");
               return -1;
           }
           yes = 1;
           if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
                   (char *) &yes, sizeof(yes)) == -1) {
               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)) == -1) {
               perror("bind");
               close(s);
               return -1;
           }
           printf("accepting connections on port %d\n", 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)) == -1) {
               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)) == -1) {
               perror("connect()");
               shutdown(s, SHUT_RDWR);
               close(s);
               return -1;
           }
           return s;
       }

       #define SHUT_FD1 do {                                \
                            if (fd1 >= 0) {                 \
                                shutdown(fd1, SHUT_RDWR);   \
                                close(fd1);                 \
                                fd1 = -1;                   \
                            }                               \
                        } while (0)

       #define SHUT_FD2 do {                                \
                            if (fd2 >= 0) {                 \
                                shutdown(fd2, SHUT_RDWR);   \
                                close(fd2);                 \
                                fd2 = -1;                   \
                            }                               \
                        } while (0)

       #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\n\tfwd <listen-port> "
                        "<forward-to-port> <forward-to-ip-address>\n");
               exit(EXIT_FAILURE);
           }

           signal(SIGPIPE, SIG_IGN);

           forward_port = atoi(argv[2]);

           h = listen_socket(atoi(argv[1]));
           if (h == -1)
               exit(EXIT_FAILURE);

           for (;;) {
               int r, nfds = 0;
               fd_set rd, wr, er;

               FD_ZERO(&rd);
               FD_ZERO(&wr);
               FD_ZERO(&er);
               FD_SET(h, &rd);
               nfds = max(nfds, h);
               if (fd1 > 0 && buf1_avail < BUF_SIZE) {
                   FD_SET(fd1, &rd);
                   nfds = max(nfds, fd1);
               }
               if (fd2 > 0 && buf2_avail < BUF_SIZE) {
                   FD_SET(fd2, &rd);
                   nfds = max(nfds, fd2);
               }
               if (fd1 > 0 && buf2_avail - buf2_written > 0) {
                   FD_SET(fd1, &wr);
                   nfds = max(nfds, fd1);
               }
               if (fd2 > 0 && buf1_avail - buf1_written > 0) {
                   FD_SET(fd2, &wr);
                   nfds = max(nfds, fd2);
               }
               if (fd1 > 0) {
                   FD_SET(fd1, &er);
                   nfds = max(nfds, fd1);
               }
               if (fd2 > 0) {
                   FD_SET(fd2, &er);
                   nfds = max(nfds, fd2);
               }

               r = select(nfds + 1, &rd, &wr, &er, NULL);

               if (r == -1 && errno == EINTR)
                   continue;

               if (r == -1) {
                   perror("select()");
                   exit(EXIT_FAILURE);
               }

               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 == -1) {
                       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 == -1)
                           SHUT_FD1;
                       else
                           printf("connexion de %s\n",
                                   inet_ntoa(client_address.sin_addr));
                   }
               }

               /* NB : lecture des donnees hors bande avant les lectures normales */

               if (fd1 > 0)
                   if (FD_ISSET(fd1, &er)) {
                       char c;

                       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;

                       r = recv(fd2, &c, 1, MSG_OOB);
                       if (r < 1)
                           SHUT_FD2;
                       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;
                   }

               /* Verifie si l'ecriture de donnees a rattrape la lecture de donnees */

               if (buf1_written == buf1_avail)
                   buf1_written = buf1_avail = 0;
               if (buf2_written == buf2_avail)
                   buf2_written = buf2_avail = 0;

               /* une extremite a ferme la connexion, continue
                  d'ecrire vers l'autre extremite jusqu'a 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;
           }
           exit(EXIT_SUCCESS);
       }

       Le  programme  ci-dessus  redirige correctement la plupart des types de
       connexions TCP y compris les signaux de donnees hors bande OOB transmis
       par  les  serveurs  telnet.  Il  gere  le  probleme epineux des flux de
       donnees bidirectionnels simultanes. Vous pourriez penser qu'il est plus
       efficace  d'utiliser  un  appel fork(2) et de dedier une tache a chaque
       flux. Cela devient alors plus delicat que vous ne l'imaginez. Une autre
       idee  est  de  configurer  les  entrees-sorties comme non bloquantes en
       utilisant fcntl(2). Cela pose egalement probleme puisque ca vous  force
       a utiliser des timeouts inefficaces.

       Le programme ne gere pas plus d'une connexion a la fois bien qu'il soit
       aisement extensible a une telle fonctionnalite en utilisant  une  liste
       chainee  de  tampons  --  un  pour chaque connexion. Pour l'instant, de
       nouvelles connexions provoquent l'abandon de la connexion courante.

VOIR AUSSI

       accept(2), connect(2), ioctl(2), poll(2), read(2), recv(2),  select(2),
       send(2),    sigprocmask(2),   write(2),   sigaddset(3),   sigdelset(3),
       sigemptyset(3), sigfillset(3), sigismember(3), epoll(7)

COLOPHON

       Cette page fait partie de  la  publication  3.27  du  projet  man-pages
       Linux.  Une description du projet et des instructions pour signaler des
       anomalies      peuvent      etre       trouvees       a       l'adresse
       <URL:http://www.kernel.org/doc/man-pages/>.

TRADUCTION

       Depuis  2010,  cette  traduction est maintenue a l'aide de l'outil po4a
       <URL:http://po4a.alioth.debian.org/>   par   l'equipe   de   traduction
       francophone        au        sein        du       projet       perkamon
       <URL:http://perkamon.alioth.debian.org/>.

       Stephan          Rafin          (2002),          Alain           Portal
       <URL:http://manpagesfr.free.fr/> (2006).   Julien  Cristau  et l'equipe
       francophone de traduction de Debian (2006-2009).

       Veuillez  signaler  toute  erreur   de   traduction   en   ecrivant   a
       <debian-l10n-french@lists.debian.org> ou par un rapport de bogue sur le
       paquet manpages-fr.

       Vous pouvez toujours avoir acces a la version anglaise de  ce  document
       en utilisant la commande << man -L C <section> <page_de_man> >>.