Envoi et réception de chaînes via un socket TCP séparément

J’ai un serveur et un client TCP, avec un socket établi. Disons que j’ai le cas suivant:

SERVEUR:

char *fn = "John"; char *ln = "Doe"; char buffer[512]; strcpy(buffer, fn); send(*socket, buffer, strlen(buffer), 0); strcpy(buffer, ln); send(*socket, buffer, strlen(buffer), 0); 

CLIENT:

 char *fn; char *ln; char buffer[512]; bytes = recv(*socket, buffer, sizeof(buffer), 0); buffer[bytes] = '\0'; strcpy(fn, buffer); bytes = recv(*socket, buffer, sizeof(buffer), 0); buffer[bytes] = '\0'; strcpy(ln, buffer); printf("%s", fn); printf("%s", ln); 

Résultat attendu: Je souhaite recevoir chaque chaîne séparément (car je les enregistre dans différentes variables). Au lieu de cela, le premier recv () obtient le fn “John” et le “Doe” concaténés “JohnDoe”, et le programme rest bloqué. le deuxième recv () … depuis que j’ai déjà fait l’envoi.

J’ai essayé ce qui suit: – Ajout de \ 0 aux chaînes fn et ln comme suit:

 char *fn = "John\0"; char *ln = "Doe\0"; 

Mais le problème a persisté.

Y a-t-il une sorte de condition que je peux imposer pour que chaque chaîne soit reçue séparément?

MODIFIER POUR AJOUTER PLUS DE QUESTIONS:

1) Pourquoi, dans certains cas, l’envoie-t-il réellement séparément, et d’autres conjointement?

2) Dois-je envoyer () et recv () alternativement peut-être? Dans d’autres parties de mon code, il semble que le système s’autorégule et ne reçoive que les bonnes chaînes au bon moment, sans que je doive vérifier. Est-ce que cela fait l’affaire?

3) À propos de l’envoi d’un en-tête avec la longueur de la chaîne que je vais envoyer, comment parsingr la chaîne entrante pour savoir où se scinder? Tous les exemples seraient géniaux.

4) Je vais certainement vérifier si je reçois quelque chose de plus gros que mon tampon, merci de le signaler.

Edit 2:

5) Puisque je mets toujours des objects dans un tableau de caractères de tampon de taille 512. Chaque opération d’envoi ne devrait-elle pas prendre la taille complète du tampon, même si j’envoie une chaîne d’une lettre? C’est ce qui déroute. J’ai “John” mais je le mets dans un tableau de taille 512 et l’envoie. Cela ne devrait pas remplir le tampon d’envoi. La fonction recv () vide donc le tampon réseau en extrayant également tout le tableau de taille. 512?

Premièrement, lorsque le client appelle recv(*socket, buffer, sizeof(buffer), 0); , il recevra jusqu’à sizeof (tampon) caractères (ici 512) du réseau. Cela provient du tampon réseau et n’a rien à voir avec le nombre d’appels send sur le serveur. recv ne recherche ni \0 ni aucun autre caractère – il s’agit d’une extraction binary du tampon réseau. Il lira soit la totalité du tampon réseau, soit les caractères sizeof(buffer) .

Vous devez vérifier dans le premier recv pour voir s’il comporte à la fois le nom et le nom de famille et le manipuler correctement.

Vous pouvez le faire en demandant au serveur d’envoyer la longueur des chaînes en tant que premiers octets d’un stream (un “en-tête”) ou en balayant les données reçues pour voir s’il existe deux chaînes.

Vous devez vraiment effectuer des vérifications chaque fois que vous appelez recv – que se passe-t-il si la chaîne est supérieure à 512 octets? Ensuite, vous devez appeler recv plusieurs fois pour obtenir la chaîne. Et si vous obtenez la première chaîne et seulement la moitié de la deuxième? Habituellement, ces deux cas ne surviennent que lorsqu’il s’agit de traiter de plus grandes quantités de données, mais je l’ai déjà vu dans mon propre code auparavant. Il est donc préférable d’intégrer de bons contrôles à recv même avec de petites chaînes comme celle-ci. Si vous pratiquez de bonnes tactiques de codage dès le début, vous n’aurez pas autant de maux de tête sur la route.

La bonne chose à faire est de joindre les données envoyées à un en-tête. Ainsi, vous transmettez la taille du message, y compris la taille du message, puis vous pouvez déterminer la longueur du message de l’autre côté.

John a 4 caractères, donc vous avez la longueur, quelque chose comme “0004John”, alors vous saurez quand arrêter de lire. Vous pouvez également append une commande à l’en-tête, ce qui est très courant. Ainsi, par exemple, le prénom pourrait être 1 et le deuxième nom 2;

“01004JOHN” par exemple serait placé dans le tampon et envoyé.

Pour ce faire, vous ajoutez des éléments à la mémoire tampon, puis incrémentez le point d’insertion dans la mémoire tampon de la taille des valeurs que vous avez ajoutées. Vous pouvez l’utiliser pour append de nombreuses parties au tampon. * Assurez-vous simplement de ne pas dépasser la taille du tampon.

Rappelez-vous que ces exemples ne sont pas corrects, car vous ne transmettez pas la représentation sous forme de chaîne du nombre, mais simplement le nombre; il s’agirait donc d’un long int 1, long int 4 puis de caractères, ou d’unicode, dans tous les cas de 4 caractères.

TCP est orienté stream et non pas datagramme. Si c’était le dernier cas, vos affaires fonctionneraient très bien. Vous avez les options suivantes:

  • utiliser SCTP
  • utilisez UDP si vous pouvez vous permettre de perdre de la fiabilité
  • séparez les chaînes de la manière que vous pouvez utiliser, soit en ajoutant une balise de longueur, par exemple, soit en ajoutant un octet NUL pour terminer chaque chaîne.

Pour ce dernier, vous ne feriez que l’ send(*socket, buffer, strlen(buffer)+1, 0); pour inclure le NUL qui est ici quand même, et l’expéditeur aurait à plusieurs resockets recv() et trouver un terminateur de chaîne jusqu’à ce qu’il ait trouvé 2 chaînes.

Notez que vous devez faire attention avec strcpy() : utilisez-le uniquement si vous êtes absolument sûr que la chaîne que vous écrivez est correcte.

Votre récepteur fait

 bytes = recv(*socket, buffer, sizeof(buffer), 0); buffer[bytes] = '\0'; 

C’est mauvais parce que, si le tampon est plein, donc bytes == sizeof(buffer) (ce qui peut arriver dans des situations plus complexes), buffer[bytes] = '\0' écrit au-delà du tampon. SO utiliser

 bytes = recv(*socket, buffer, sizeof(buffer) - 1, 0); 

et vous pouvez faire avec bonheur

 buffer[bytes] = '\0'; 

.

au lieu de sizeof (tampon), utilisez strlen (fn); donc, il ne transmettra que le nombre exact d’octets. Si vous avez besoin d’un terminateur nul, utilisez strlen (fn) +1, mais n’oubliez pas de concaténer un terminateur nul avec strcat ().

de même, si vous envoyez toute la taille de la mémoire tampon sans nettoyage avec memset, vous aurez également des déchets, alors méfiez-vous-en.