Traitement des informations
(en mode connecté)
Les includes
Si ce n'est déjà fait, certains includes seront nécessaires:
#include <sys/types.h>
#include <sys/socket.h>
Lire ou écrire des données
Comme vous le savez déjà, sous Unix, tout est fichier. Par conséquent, il sera tout à fait possible d'utiliser les fonctions read ou write pour lire ou envoyer des données. Il suffira d'utiliser le descripteur de socket comme descripteur de fichier...Je n'en dirais pas plus.
Mais il existe des fonctions plus appropriées:
Tout d'abord envoyer une chaîne à destination d'une autre socket:
int send(int s, const void *msg, size_t len, int flags);
Send ne peut
être utilisé qu'avec les sockets connectées !
En entrée:
s est l'identifiant du socket
msg est un buffer contenant le message à envoyer
len est la longueur du texte à envoyer
flags contenant une ou plusieurs options:
Valeur | Désignation |
MSG_OOB | Permet d'émettre des données hors-bande sur un socket qui l'autorise (ex. SOCK_STREAM) |
MSG_DONTROUTE | Ne pas passer par une passerelle mais uniquement vers les hôtes directement connecté au réseau |
MSG_DONTWAIT | Active le mode non-bloquant (retournera EAGAIN pour indiquer que cela aurait du être bloquant) |
MSG_NOSIGNAL | Ne pas envoyer le signal SIGPIPE lorsque le correspondant coupe la connexion. EPIPE sera renvoyé à la place. |
En sortie:
La fonction retoutne -1 si erreur et errno contient le code erreur, sinon, il s'agit de la taille du texte transmis.
Voici quelques exemples de codes erreurs:
Valeur | Désignation |
EBADF | Descripteur de socket invalide. |
ENOTSOCK | L'argument s n'est pas une socket. |
EFAULT | Un paramètre pointe en dehors de l'espace d'adresssage accessible. |
EMSGSIZE | La socket nécessite une emission intégrale du message mais la taille de celui-ci ne le permet pas. |
EAGAIN ou EWOULDBLOCK | La socket est non-bloquante et l'opération demandée bloquerait. |
ENOBUFS | La file d'émission de l'interface réseau est pleine.Cause: panne ou saturation passagère |
EINTR | Un signal a été reçu |
ENOMEM | Pas assez de mémoire pour le noyau. |
EINVAL | Un argument invalide a été transmis. |
EPIPE | L'écriture est impossible.Le processus recevra également un signal SIGPIPE sauf s'il a activée l'option MSG_NOSIGNAL. |
Puis recevoir une chaîne provenant d'une autre socket:
int recv(int s, void *buf, int len, unsigned int flags);
int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, socklen_t *fromlen);
recvfrom pourra
servir à la lecture de données que la socket soit orientée
connexion ou non. Dans notre cas, càd en mode connecté, from devra
être nul.
En entrée:
s est le descripteur de socket
buf est une zone mémoire qui recevra le texte
len est la taille du buffer.
flags est un drapeau permettant de gérer les options suivantes:
Valeur | Désignation |
MSG_OOB | Permet d'émettre des données hors-bande sur un socket qui l'autorise (ex. SOCK_STREAM) |
MSG_PEEK | Lire les données en attente dans le file sans les retirer. Une lecture ultérieur pourra alors récupérer ces données. |
MSG_WAITALL | Attendre (lecture bloquante) jusqu'à la complétude de la requète. (sauf signaux, ou erreur/déconnexion) |
MSG_ERRQUEUE | Lire les erreurs provenant de la file d'erreur de la socket. |
Ces trois routines renvoient la longueur du message si elles réussissent. Si un message est trop long pour tenir dans le buffer, les octets supplémentaires peuvent être abandonnés suivant le type de socket utilisé.
Si aucun message n'est disponible sur la socket, les fonctions de réception se mettent en attente, à moins que la socket soit non bloquante (voir ci-après ) auquel cas la valeur -1 est renvoyée, et errno est positionnée à EAGAIN.
Les fonctions de réception renvoient normalement les données disponibles dans la limite du paramètre len sans attendre d'avoir reçu le nombre exact réclamé.
Les fonctions
send () et recv () sont bloquantes (ou plus exactement: le socket). On pourra
les rendre non bloquantes en utilisant:
Sous Windows:
u_long arg = 1;
ioctlsocket (socket, FIONBIO, &arg);
Pour le rendre de nouveau bloquant, passé la valeur 0 dans arg.
Sous Linux:
fcntl(socket, F_SETFL, O_NONBLOCK);
avec socket le descripteur du socket !
Suite à un send de données d'une taille précise, il n'est pas obligatoire que recv retourne en une seule opération l'ensemble de ces données. Il sera donc peut être nécessaire de faire un second, un troisième ,... recv pour obtenir le reste des données. Il faudra peut être mettre en place un système indiquant lors du send la taille totale des données effectivement envoyées, ce qui permettra lors de recv de savoir si le paquet de données est complet ou si il est nécessaire de relancer un recv.