Programmation de sockets: recv ()

J’ai une application dans laquelle différentes entités communiquent entre elles via des sockets et j’utilise le langage de programmation C. Lorsqu’une entité envoie un long message à une autre entité, la fonction recv () peut lire ce message par parties. Par conséquent, je dois reconstruire le message du côté du destinataire en ajoutant toutes les parties reçues.

Ma question est une question de programmation de socket générale liée à recv (). Comment recv () sait-il qu’un message a été entièrement lu? Devrais-je terminer un message avec un caractère spécial tel que “\ n”? ou dois-je envoyer la taille du message en tant qu’en-tête? Quelle est la pratique courante?

Comme vous l’avez remarqué, avec les sockets de stream, il n’y a pas de notion intégrée de limites de message. Vous devez créer un moyen de déterminer la fin du message dans votre protocole au niveau de l’application.

Les deux options que vous avez suggérées sont communes: soit un préfixe de longueur (commençant chaque message par la longueur du message), soit un délimiteur de fin de message (pouvant par exemple être une nouvelle ligne dans un protocole texte ). Une troisième option, moins utilisée, consiste à imposer une taille fixe à chaque message. Des combinaisons de ces options sont également possibles – par exemple, un en-tête de taille fixe qui inclut une valeur de longueur.

Lorsque vous utilisez send () et recv (), vous spécifiez une taille de tampon.

Si vous utilisez un tel moyen pour envoyer un message:

send(new_socket,message,strlen(message),0); 

Le troisième paramètre est la taille de votre tampon.

Une façon de savoir si vous avez envoyé un paquet avec succès est si vous utilisez des sockets TCP, send() et recv() renverraient les mêmes valeurs. Vous pouvez vérifier cela du côté de l’expéditeur en vérifiant si la taille du message est identique à la valeur renvoyée par send() .

Pour vérifier du côté récepteur, le moyen le plus simple consiste à append le délimiteur de fin de chaîne \0 à votre chaîne.

Dès que l’on commence à faire de la programmation réseau en C, on comprend vite pourquoi les langages de haut niveau sont populaires! Fondamentalement, ils ont beaucoup de fonctionnalités intégrées dans lesquelles vous vous retrouvez bientôt en souhaitant que C ait un peu plus à offrir!

Tout d’abord, je vous encourage fortement à regarder ZeroMQ ( http://zeromq.org/bindings:c ) et sa liaison en C. Cela fait une bonne partie de l’horrible travail de l’âne pour ce qui est des relations, de la démarcation des messages, etc. De plus, c’est rapide à l’exécution; c’est rapide à développer avec et rapide à exécuter, les marques d’une bonne bibliothèque.

ZeroMQ est sur le point d’être la bibliothèque de sockets parfaite. La seule chose qu’il ne fait pas encore (AFAIK) est de surveiller activement la connexion pour voir si elle s’est effondrée – vous découvrez uniquement si vous essayez d’envoyer quelque chose. Si vous souhaitez contrôler l’intégrité de la connexion, vous devez envoyer régulièrement vos propres messages de test de connexion.

Deuxièmement, je vous encouragerais à envisager la sérialisation. Dès que vous commencez à avoir des structures de données complexes qui pointent vers la mémoire allouée, vous commencez à entrer dans un territoire complexe et difficile. Face à ce problème, j’ai choisi ASN.1 pour définir et sérialiser mes structures de données à l’aide des bibliothèques et des outils d’Objective Systems ( http://www.obj-sys.com/index.php ). Cela coûte de l’argent, prend un peu de temps pour s’y habituer, mais j’ai trouvé cela extrêmement utile en termes de gain de temps en développement.

En plus des routines de sérialisation, ils vous fournissent des extras très pratiques que C ne fournit pas. Par exemple, leur générateur de code vous donnera des routines pour copier les types de données, ce qui est très pratique si ce type de données est une structure remplie de pointeurs référençant la mémoire allouée.

Il existe probablement aussi des outils gratuits et des bibliothèques. Les tampons de protocole de Google, qui possèdent une liaison C ( http://code.google.com/p/protobuf-c/ ), constituent une bonne alternative.