Corruption de données de socket

Je travaille sur un client de socket simple, qui envoie une simple lettre “p” au serveur, puis lit la réponse du serveur. Cela fonctionne pleinement, sauf pour un problème déroutant. La toute première fois que le socket est lu (cela se produit dans une boucle), les données sont tronquées et corrompues, avec des résultats tels que “ÿýÿû” et “µÞv”. Toutes les données reçues après la première réponse sont correctes et valides.

Le code que j’utilise pour recevoir est:

int n; char buffer[256]; bzero(buffer,256); strcpy(buffer, "p"); n = write(manSock,buffer,256); if (n < 0) { error("ERROR writing to management server"); } bzero(buffer,256); n = read(manSock,buffer,256); if (n < 0) { error("ERROR reading from management server"); } return buffer; 

manSock est le descripteur de fichier de socket.

Des idées sur pourquoi cela se produit?

Vous devez n’envoyer que jusqu’à la longueur (strlen) du tampon. Il est recommandé d’envoyer toujours la longueur du tampon avant d’envoyer les données.

 int len; len = strlen(buffer); n = write(manSock,&len , sizeof(int)); if (n < 0) { error("ERROR writing to len management server"); } n = write(manSock,buffer,strlen(buffer)); if (n < 0) { error("ERROR writing to management server"); } bzero(buffer,256); n = read(manSock,&len,sizeof(int)); if (n < 0) { error("ERROR reading len from management server"); } n = read(manSock,buffer,len); if (n < 0) { error("ERROR reading from management server"); } 

Cela ne semble pas être un problème lié aux sockets, mais à la gestion de la mémoire.

Vous semblez renvoyer un pointeur sur la mémoire qui n’est valide que localement pour la fonction.

En supposant que votre “vrai” code ressemble à ceci

 char * foo(void) { char buffer[256]; /* read into buffer */ return buffer; } void bar (void) { char * p = foo(); printf("%s\n", p); } 

alors p fait référence à la mémoire invalide après le retour de foo() , le tampon ayant été implicitement libéré lors du retour de foo() .

Pour résoudre ce problème

  • soit allouer un buffer dynamic dans foo() utilisant malloc() , calloc() ou strdup()

     char * foo(void) { char * buffer = malloc(256); memset(buffer, 0, 256); /* read into buffer */ return buffer; } 

    ou

     char * foo(void) { char * buffer = calloc(256, sizeof(*buffer)); /* read into buffer */ return buffer; } 

    ou

     char * foo(void) { char buffer[256] = {0}; /* read into buffer */ return strdup(buffer); } 
  • ou transmettre à foo() une référence à un tampon en cours d’atsortingbution dans bar() (ou supérieur).

     void foo(char * buffer) { /* read into where buffer points */ } void bar(void) { char buffer[256] = {0}; foo(buffer); /* print buffer */ } 

Votre code tel qu’il existe actuellement (en supposant qu’il s’agisse d’une fonction) est mauvais, même si vous avez suivi les conseils donnés dans les autres réponses et commentaires concernant les fonctions d’ write et de read .

La raison en est que vous retournez un tableau défini localement (en fait l’adresse du premier élément), un buffer , ce qui constitue un comportement indéfini . Ainsi, si vous récupérez la valeur de retour, la buffer n’est plus valide et pourrait éventuellement contenir des données erronées, même si vous l’avez renseignée avec des données valides dans la fonction.

La balise C ++ a été supprimée, mais si vous utilisez réellement C ++, vous pouvez toujours copier les résultats dans un std::ssortingng et le renvoyer à la place:

 std::ssortingng someFunc() { int n; char buffer[256]; //.. your code goes here //... return std::ssortingng(buffer, len); // where len is the number of characters read } 

Si vous utilisez C, demandez à l’utilisateur de vous transmettre le tampon et de le compléter dans la fonction. Ne créez pas de tableaux locaux et ne les renvoyez pas, c’est ce qui compte.

Vous avez mal conçu votre API

  1. Vous retournez l’adresse d’un tampon local, qui n’existe pas et peut être écrasé après l’appel.
  2. Vous jetez la longueur renvoyée par recv (), ainsi l’appelant n’a aucun moyen de savoir quelle quantité de mémoire tampon est valide, même si vous avez fixé (1) d’une manière ou d’une autre.

Vous avez besoin de l’ appelant pour fournir le tampon et vous devez renvoyer la longueur. Cela fait que votre signature de méthode ressemble remarquablement à celle de recv (). En d’autres termes, vous n’avez probablement pas vraiment besoin de cette méthode. L’appelant pourrait simplement appeler recv ().