Linux |
CentOS 4.8 |
|
accept(2) |
accept − Accepter une connexion sur une socket. |
#include <sys/types.h> |
accept est utilisé généralement avec des processus serveurs orientés−connexion. Cet appel système est employé avec les sockets utilisant un protocole en mode connecté (SOCK_STREAM, SOCK_SEQPACKET et SOCK_RDM) L’appel-système accept extrait la première connexion de la file des connexions en attente, crée une nouvelle socket avec essentiellement les mêmes propriétés que sock et alloue un nouveau descripteur de fichier pour cette socket. La socket originale sock reste ouverte sans être modifiée par l’appel-système. Remarquez que les attributs correspondant aux propriétés du descripteur de fichier (tout ce qu’on peut configurer avec l’option F_SETFL de setfl() comme l’état non-bloquant ou asynchrone), ne sont pas hérités durant un accept. L’argument sock est une socket qui a été créée avec la fonction socket(2). On lui a affecté une adresse avec bind(2). Enfin on a indiqué au système, avec listen(2) qu’elle désirait recevoir des connexions entrantes. L’argument adresse est un paramètre résultat qui est renseigné avec l’adresse de l’entité se connectant, telle qu’elle est connue par la couche de communication. Le format exact du paramètre adresse est fonction du domaine dans lequel la communication s’établit. (Voir socket(2) et la page de manuel correspondant au protocole). Le paramètre-résultat longueur est renseigné avec la longueur (en octets) de l’adresse retournée. Ce paramètre doit initialement contenir la longueur du paramètre adresse. Si adresse est NULL, rien n’est écrit. S’il n’y a pas de connexion en attente dans la file, et si la socket est bloquante, accept se met en attente d’une connexion. Si la socket est non-bloquante, et qu’aucune connexion n’est présente dans la file, accept retourne une erreur EAGAIN. Lorsque l’on désire accepter des connexions sur plusieurs sockets simultanément, il est important de ne pas rester bloqué en attente avec l’appel accept sur une seule d’entre elles. Il est alors possible d’utiliser l’appel-système select(2) ou poll(2) sur l’ensemble des sockets pour déterminer la disponibilité des données à lire, et d’effectuer ensuite l’appel accept sur celles qui ont effectivement reçu des demandes de connexion. Il est également possible de demander à une socket d’envoyer le signal SIGIO lorsqu’une activité la concernant se produit, voir socket(7) pour plus de détails. Pour certains protocoles nécessitant une confirmation explicite, comme DECNet, accept peut être considéré comme extrayant simplement la connexion suivante de la file, sans demander de confirmation. Cette confirmation peut être effectuée par une simple lecture ou écriture sur le nouveau descripteur de fichier, et un rejet peut être effectué en fermant simplement la nouvelle socket. Pour le moment, seul DECNet se comporte ainsi sous Linux. |
Il n’y a pas nécessairement de connexion en attente après la réception de SIGIO ou après que select(2) ou poll(2) indiquent quelquechose à lire. En effet la connexion peut avoir été annulée à cause d’une erreur réseau asynchrone ou par un autre thread avant que accept ne se termine. Si cela se produit, l’appel bloquera en attendant une autre connexion. Pour s’assurer que accept ne bloquera jamais, la socket sock transmise doit avoir l’attribut O_NONBLOCK positionné (voir socket(7)). |
accept renvoie −1 en cas d’erreur. S’il réussit il renvoie un entier non-négatif, constituant un descripteur pour la nouvelle socket. |
Sous Linux, accept renvoie les erreurs réseau déjà en attente sur la socket comme une erreur de l’appel-système. Ce comportement diffère d’autres implémentations des sockets BSD. Pour un comportement fiable, une application doit détecter les erreurs réseau définies par le protocole après le accept et les traiter comme des erreurs EAGAIN, en réitérant le mécanisme. Dans le cas de TCP/IP, ces erreurs sont EPROTO, ENOPROTOOPT, EHOSTDOWN, ENONET, EHOSTUNREACH, EOPNOTSUPP, et ENETUNREACH. |
EAGAIN ou EWOULDBLOCK |
La socket est non-bloquante et aucune connexion n’est présente dans la file. |
EBADF |
sock est un descripteur invalide. |
ENOTSOCK |
sock est un descripteur de fichier, pas de socket. |
EOPNOTSUPP |
La socket de référence n’est pas de type SOCK_STREAM. |
EFAULT |
adresse pointe en-dehors de l’espace d’adressage accessible. |
|
EPERM |
Certaines règles de firewall du noyau interdisent les connexions. |
ENOBUFS, ENOMEM |
Par assez de mémoire disponible. En général, cette erreur due à la taille limitée du buffer des sockets, et pas à la mémoire système proprement dite. |
De plus, des erreurs dues au protocole réseau peuvent être renvoyées. Certains noyaux Linux peuvent donner les erreurs EMFILE, EINVAL, ENOSR, ENOBUFS, EPERM, ECONNABORTED, ESOCKTNOSUPPORT, EPROTONOSUPPORT, ETIMEDOUT. L’erreur ERESTARTSYS peut être rencontrée durant un suivi dans un débogueur. |
Un scénario typique de mise en oeuvre de serveur orienté connexion est le suivant : int pnum; int sock; int nouvelle; sock = socket (famille, type, 0); if (sock < 0) { perror ("socket"); exit (1); } if (bind (sock, & mon_adresse, longueur_adresse) < 0) { perror ("bind"); exit (1); } if (listen (sock, 5) < 0) { perror ("listen"); exit (1); } while (1) { nouvelle = accept (sock, & adresse_client, & lg_adresse_client); if (nouvelle < 0) { perror ("accept"); exit (1); } if ((pnum = fork ()) == 0) { /* Processus fils */ close (sock); Traiter_le_client (nouvelle); exit (0); } if (pnum > 0) { /* Processus père */ close (nouvelle); /* Attendre la connexion suivante */ continue; } perror ("fork"); exit (1); } |
SVr4, BSD 4.4. La fonction accept est apparue dans BSD 4.2. La page de manuel BSD documente cinq erreurs possibles (EBADF, ENOTSOCK, EOPNOTSUPP, EWOULDBLOCK, EFAULT). SUSv2 documente les erreurs EAGAIN, EBADF, ECONNABORTED, EFAULT, EINTR, EINVAL, EMFILE, ENFILE, ENOBUFS, ENOMEM, ENOSR, ENOTSOCK, EOPNOTSUPP, EPROTO, EWOULDBLOCK. La version Linux de accept ne fait pas hériter les attributs des sockets comme O_NONBLOCK. Ce comportement est différent d’autres implémentations, comme BSD. Les programmes portables ne doivent pas s’appuyer sur cette particularité, et doivent reconfigurer les attributs désirés sur la socket renvoyée par accept. |
Le troisième argument de accept était, à l’origine, déclaré comme un ‘int *’ (et c’est le cas dans libc4 et libc5 ainsi que pour beaucoup d’autres systèmes comme BSD 4.*, SunOS 4, SGI). Une proposition de standard POSIX 1003.1g l’a modifié en ‘size_t *’ et c’est ce qu’utilise SunOS. Les dernières propositions POSIX en ont fait un ‘socklen_t *’, ce que suivent les spécifications Single Unix, et la glibc2. Pour citer Linus Torvalds: ‘Toute bibliothèque sensée doit garder "socklen_t" équivalent à un int. Toute autre chose invaliderait tout le niveau des sockets BSD. POSIX l’avait d’abord remplacé par un size_t, et je m’en suis plaint violemment (ainsi que d’autres heureusement, mais bien entendu pas tant que ça). Le remplacement par un size_t est complètement inutile car size_t à exactement la même taille qu’un int sur les architectures 64 bits par exemple. Et il a la même taille qu’un "int" parce que c’était ainsi qu’étaient définies les sockets BSD. Finalement, les gens de POSIX ont compris et ont créé un "socklen_t". Ils n’auraient jamais dû y toucher, mais une fois commencé, ils ont décidé de créer un type spécifique, pour des raisons encore inavouées (il y a probablement quelqu’un qui ne veut pas perdre la face en expliquant que le premier travail était stupide et ils ont simplement renommé leur bricolage).’’ |
bind(2), connect(2), listen(2), select(2), socket(2) |
Christophe Blaess, 1997. |
accept(2) |