NOM

recv, recvfrom, recvmsg - Recevoir un message d'un socket

BIBLIOTHÈQUE

Bibliothèque C standard ( libc, -lc)

SYNOPSIS

#include <sys/socket.h>
ssize_t recv(int sockfd, void buf[.len], size_t len,
                 int flags);
ssize_t recvfrom(int sockfd, void buf[restrict .len], size_t len,
                 int flags,
                 struct sockaddr *_Nullable restrict src_addr,
                 socklen_t *_Nullable restrict addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

DESCRIPTION

Les appels système recv(), recvfrom() et recvmsg() sont utilisés pour recevoir des messages depuis un socket, et peuvent servir sur un socket orienté connexion ou non. Cette page décrit dans un premier temps les fonctionnalités communes de ces trois appels système, puis précise ensuite ce qui les différencie.
La seule différence entre recv() et read(2) est la présence de flags. Si l’argument flags est absent, recv() est généralement équivalent à read(2) (mais voir les NOTES). De plus, l'appel suivant

recv(sockfd, buf, len, flags);

est équivalent à :

recvfrom(sockfd, buf, len, flags, NULL, NULL);

Ces trois appels renvoient la longueur du message s'ils réussissent. Si un message est trop long pour tenir dans le tampon, les octets supplémentaires peuvent être abandonnés suivant le type de socket utilisé.
Si aucun message n'est disponible sur le socket, les appels à réception se mettent en attente, à moins que le socket soit non bloquant (voir fcntl(2)), auquel cas la valeur -1 est renvoyée et errno est positionnée à EAGAIN ou EWOULDBLOCK. Les appels à réception renvoient normalement les données disponibles, jusqu’au montant demandé, sans attendre d'avoir reçu le nombre exact réclamé.
Une application peut avoir recours à select(2), poll(2), ou epoll(7) pour savoir si des données supplémentaires arrivent dans le socket.

Le paramètre des attributs

L'argument flags est constitué à partir d'un OU binaire entre une ou plusieurs des valeurs suivantes :
MSG_CMSG_CLOEXEC (recvmsg() uniquement ; depuis Linux 2.6.23)
Positionner l'attribut « close-on-exec » pour le descripteur de fichier reçu à l’aide d’un descripteur de fichier de domaine UNIX en utilisant l'opération SCM_RIGHTS (décrite dans unix(7)). Cet attribut est utile pour les mêmes raisons que l'attribut O_CLOEXEC de open(2).
MSG_DONTWAIT (depuis Linux 2.2)
Activer l'opération non bloquante ; si elle bloque, l'appel échoue avec l'erreur EAGAIN ou EWOULDBLOCK. Cela fournit un comportement identique à la définition de l'attribut O_NONBLOCK (à l'aide de l'opération F_SETFL de fcntl(2)), sauf que MSG_DONTWAIT est une option pour chaque appel tandis que O_NONBLOCK est un paramètre sur la description du fichier ouvert (voir open(2)), qui touchera tous les threads du processus appelant ainsi que d'autres processus détenant des descripteurs de fichier se rapportant à la même description de fichier ouvert.
MSG_ERRQUEUE (depuis Linux 2.2)
Cet attribut demande que les erreurs soient reçues depuis la file d'erreur du socket. Les erreurs sont transmises dans un message annexe dont le type dépend du protocole ( IP_RECVERR pour IPv4). Il faut alors fournir un tampon de taille suffisante. Consultez cmsg(3) et ip(7) pour plus de détails. Le contenu du paquet original qui a causé l'erreur est passé en tant que données normales dans msg_iovec. L'adresse de destination originale du datagramme ayant causé l'erreur est fournie dans msg_name.
L'erreur est contenue dans une structure sock_extended_err :

#define SO_EE_ORIGIN_NONE    0
#define SO_EE_ORIGIN_LOCAL   1
#define SO_EE_ORIGIN_ICMP    2
#define SO_EE_ORIGIN_ICMP6   3
struct sock_extended_err { uint32_t ee_errno; /* numéro d'erreur */ uint8_t ee_origin; /* origine de l'erreur */ uint8_t ee_type; /* type */ uint8_t ee_code; /* code */ uint8_t ee_pad; /* remplissage */ uint32_t ee_info; /* données supplémentaires */ uint32_t ee_data; /* autres données */ /* Des données supplémentaires peuvent suivre */ };
struct sockaddr *SO_EE_OFFENDER(struct sock_extended_err *);

ee_errno contient le code errno de l'erreur en file d’attente. ee_origin est le code d'origine d’où l’erreur provient. Les autres champs sont spécifiques au protocole. La macro SO_EE_OFFENDER renvoie un pointeur sur l'adresse de l'objet réseau ayant déclenché l'erreur, en donnant un pointeur sur le message annexe. Si cette adresse n'est pas connue, le membre sa_family de la structure sockaddr contient AF_UNSPEC et les autres champs de la structure sockaddr sont indéfinis. Le contenu du paquet ayant déclenché l'erreur est transmis en données normales.
Pour les erreurs locales, aucune adresse n'est passée (cela peut être vérifié dans le membre cmsg_len de cmsghdr). À la réception d'une erreur, MSG_ERRQUEUE est placé dans msghdr. Après réception d'une erreur, l'erreur en attente sur le socket est régénérée en fonction de la prochaine erreur dans la file et sera transmise lors de l'opération suivante sur le socket.
MSG_OOB
Cette option demande la réception de données hors-bande qui ne seraient pas reçues dans le flux normal de données. Certains protocoles placent ces données hors-bande en tête de la file normale, et cette option n'a pas lieu d'être dans ce cas.
MSG_PEEK
Cette option fait que l’opération de réception renvoie les données du début de la queue de réception sans les enlever de cette file. Ainsi un appel à réception ultérieur renverra à nouveau les mêmes données.
MSG_TRUNC (depuis Linux 2.2)
Pour les sockets bruts (AF_PACKET), de datagrammes Internet (depuis Linux 2.4.27/2.6.8), netlink (depuis Linux 2.6.22) et de datagrammes UNIX (depuis Linux 3.4) : renvoyer la taille réelle du paquet ou datagramme, même quand il est plus grand que le tampon fourni.
Pour une utilisation avec des sockets de flux Internet, consultez tcp(7).
MSG_WAITALL (depuis Linux 2.2)
Ce drapeau demande que l'opération de lecture soit bloquée jusqu'à ce que la requête complète soit satisfaite. Toutefois, la lecture peut renvoyer quand même moins de données que prévu si un signal est reçu, si une erreur ou une déconnexion se produisent ou si les données suivantes à recevoir sont d'un type différent de celles renvoyées. Ce drapeau n'a aucun effet sur les sockets de datagramme.

recvfrom()

recvfrom() enregistre le message reçu dans le tampon buf. Le processus appelant doit préciser la taille de ce tampon dans len.
Si src_addr n'est pas NULL, et si le protocole sous-jacent fournit l'adresse de la source, celle-ci y est insérée dans le tampon désigné par src_addr. Dans ce cas, addrlen est un paramètre valeur-résultat. Avant l'appel, il doit être initialisé à la valeur de la taille du tampon associé à src_addr. En retour, addrlen est mis à jour avec la valeur réelle de l'adresse source. Cette adresse est tronquée si le tampon fourni n'a pas une taille suffisante ; dans ce cas addrlen renvoie un valeur supérieure à celle fournie lors de l'appel.
Si le processus appelant n'est pas intéressé par l'adresse de la source, src_addr et addrlen doivent avoir la valeur NULL.

recv()

L'appel recv() est normalement utilisé sur un socket connecté (voir connect(2)). Il est équivalent à l'appel :

recvfrom(fd, buf, len, flags, NULL, 0);

recvmsg()

L'appel recvmsg() utilise une structure msghdr pour minimiser le nombre de paramètres à fournir directement. Cette structure est définie dans <sys/socket.h> comme ceci :

struct msghdr {
    void         *msg_name;       /* Adresse optionnelle */
    socklen_t     msg_namelen;    /* Taille de l'adresse */
    struct iovec *msg_iov;        /* Tableau scatter/gather */
    size_t        msg_iovlen;     /* Nb. d’éléments dans msg_iov */
    void         *msg_control;    /* Données annexes, voir ci‐dessous */
    size_t        msg_controllen; /* Taille du tampon de données annexe */
    int           msg_flags;      /* Attributs du message reçu */
};

Le champ msg_name pointe vers un tampon alloué par l'appelant et qui est utilisé pour renvoyer l'adresse source lorsque le socket n'est pas connecté. L'appelant doit initialiser msg_namelen avec la taille de ce tampon avant l'appel ; si l'appel s'exécute avec succès, msg_name prend pour valeur la longueur de l'adresse renvoyée. Si l'application n'a pas besoin de connaître l'adresse source, on peut affecter la valeur NULL à msg_name.
Les champs msg_iov et msg_iovlen décrivent les emplacements de dispersion-regroupement (scatter-gather) tels qu'expliqués dans readv(2).
Le champ msg_control, de longueur msg_controllen, pointe sur un tampon utilisé pour les autres messages du protocole relatifs au contrôle, ou à d'autres données annexes. Lorsqu'on invoque recvmsg, msg_controllen doit contenir la longueur du tampon disponible dans msg_control ; lors du retour d’un appel réussi,il contiendra la longueur de la séquence du message de contrôle.
Les messages ont la forme

struct cmsghdr {
    size_t cmsg_len;    /* nombre d'octets de données, y compris l'en-tête
                           (de type socklen_t dans POSIX) */
    int    cmsg_level;   /* protocole d'origine */
    int    cmsg_type;    /* type dépendant du protocole */
/* suivi de
    unsigned char cmsg_data[]; */
};

Les données annexes ne doivent être manipulées qu'avec les macros de cmsg(3).
À titre d'exemple, Linux utilise ce mécanisme de données annexes pour transmettre des erreurs étendues, des options IP ou des descripteurs de fichier sur des sockets de domaine UNIX. Pour plus d'informations sur l'utilisation de ce mécanisme sur divers domaines de socket, voir unix(7) et ip(7).
Le champ msg_flags du msghdr est rempli au retour de recvmsg(). Il peut contenir plusieurs attributs :
MSG_EOR
indique une fin d'enregistrement, les données reçues terminent un enregistrement (utilisé généralement avec les sockets du type SOCK_SEQPACKET).
MSG_TRUNC
indique que la portion finale du datagramme a été abandonnée car le datagramme était trop long pour le tampon fourni.
MSG_CTRUNC
indique que des données de contrôle ont été abandonnées à cause d'un manque de place dans le tampon de données annexes.
MSG_OOB
est renvoyé pour indiquer que des données prioritaires ou hors-bande ont été reçues.
MSG_ERRQUEUE
indique qu'aucune donnée n'a été reçue, sauf une erreur étendue depuis la file d'erreurs.

VALEUR RENVOYÉE

Ces appels renvoient le nombre d'octets reçus si elles réussissent, ou -1 si elles échouent. Dans ce dernier cas, errno permettra d'identifier la cause de l'erreur.
Lorsque le partenaire d'un socket de flux se ferme proprement, la valeur renvoyée est 0 (c'est-à-dire la valeur habituellement renvoyée lorsqu'on arrive à la fin d'un fichier).
Les sockets de datagrammes autorisent des datagrammes de longueur nulle dans différents domaines (par exemple, les domaines UNIX et Internet). Lorsque de tels datagrammes sont reçus, la valeur renvoyée est 0.
La valeur 0 peut aussi être renvoyée lorsque le nombre d'octets demandé en réception d'un socket de flux est égal à 0.

ERREURS

Voici quelques erreurs standards déclenchées par la couche socket. Des erreurs supplémentaires peuvent être générées et renvoyées par des modules du protocole sous-jacent. Consultez leurs pages de manuel.
EAGAIN ou EWOULDBLOCK
Le socket est indiqué comme non bloquant et l'opération de réception bloquerait ou un délai de réception a été indiqué et il a expiré sans que l'on ait reçu quoi que ce soit. POSIX.1 autorise de renvoyer l'une ou l'autre des erreurs dans ce cas et n'exige pas que ces constantes aient la même valeur. Une application portable devrait donc tester les deux possibilités.
EBADF
Le paramètre sockfd est un descripteur de fichier non valable.
ECONNREFUSED
Un hôte distant a refusé la connexion réseau (généralement parce qu'il n'offre pas le service demandé).
EFAULT
Un tampon pointe en dehors de l'espace d'adressage accessible.
EINTR
Un signal a interrompu la réception avant que des données soient disponibles ; consultez signal(7).
EINVAL
Un paramètre non valable a été fourni.
ENOMEM
Pas assez de mémoire pour recvmsg().
ENOTCONN
Le socket est associé à un protocole orienté connexion et n'a pas encore été connecté (consultez connect(2) et accept(2)).
ENOTSOCK
Le descripteur de fichier sockfd ne fait pas référence à un socket.

STANDARDS

POSIX.1-2001, POSIX.1-2008, 4.4BSD (les interfaces sont apparues pour la première fois dans 4.2BSD).
POSIX.1 décrit seulement les drapeaux MSG_OOB, MSG_PEEK et MSG_WAITALL.

NOTES

Si un datagramme de taille nulle est en attente, read(2) et recv() avec un paramètre flags vide, donne un comportement différent. Dans ce cas, read(2) n'a aucun effet (le datagramme reste en attente) alors que recv() consomme le datagramme en attente.
Le type socklen_t a été inventé par POSIX. Voir aussi accept(2).
Selon POSIX.1, le champ msg_controllen de la structure msghdr devrait être de type socklen_t et le champ msg_iovlen devrait être de type int, mais ils ont tous deux le type size_t dans la glibc.
Consultez recvmmsg(2) pour plus d'informations au sujet d'un appel système propre à Linux, utilisé pour recevoir des datagrammes multiples avec un unique appel.

EXEMPLES

Un exemple d'utilisation de recvfrom() se trouve dans la page de manuel de getaddrinfo(3).

VOIR AUSSI

fcntl(2), getsockopt(2), read(2), recvmmsg(2), select(2), shutdown(2), socket(2), cmsg(3), sockatmark(3), ip(7), ipv6(7), socket(7), tcp(7), udp(7), unix(7)

TRADUCTION

La traduction française de cette page de manuel a été créée par Christophe Blaess <https://www.blaess.fr/christophe/>, Stéphan Rafin <[email protected]>, Thierry Vignaud <[email protected]>, François Micaux, Alain Portal <[email protected]>, Jean-Philippe Guérard <[email protected]>, Jean-Luc Coulon (f5ibh) <[email protected]>, Julien Cristau <[email protected]>, Thomas Huriaux <[email protected]>, Nicolas François <[email protected]>, Florentin Duneau <[email protected]>, Simon Paillard <[email protected]>, Denis Barbier <[email protected]>, David Prévot <[email protected]>, Cédric Boutillier <[email protected]>, Frédéric Hantrais <[email protected]> et Jean-Philippe MENGUAL <[email protected]>
Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à [email protected]