[C] Petit bogue sur un buffer

Petit bogue sur un buffer [C] - C - Programmation

Marsh Posté le 04-03-2012 à 14:12:36    

Salut à tous.
 
Voilà, j'ai une socket entre un tablette android et un serveur multi-thread en C qui tourne sur un linux. La tablette envoie un fichier. Donc pour ce faire j'envoi la taille de la chaine de caractère qui compose le nom du fichier, puis la chaine en elle-même, ensuite la taille du fichier puis le fichier en lui-même.
 
De cette façon je pourrais ouvrir un fichier du coté serveur avec le même nom que celui sur la tablette, et y verser le contenue du fichier dedans.
 
Bon je suis un padawan en c et mon souci est que quand je declare mon buffer avec la taille ( soit de la chaine soit du fichier ) et que je boucle sur le recv, je m'aperçois qu'il ne se vide pas. En revanche si je declare le buffer avec un valeur fichier ( genre char buffer[8] au lieu de char buffer[taille] ) la le recv se vide.
 
De même si j'envoi le nom du fichier puis le fichier j'ai une erreur genre trap quelque chose mais si j'envoi le fichier puis le nom du fichier la sa roule ( surement parce que la taille du buffer est plus grande pour le fichier que pour la chaine.
Enfin je sais pas si je suis clair. Je vous donne le code source du thread du serveur pour que vous puissiez y jeter un coup d'oeil.
 
En tout cas merci à vous!
 

Code :
  1. void* SocketHandler(void* lp)
  2. {
  3.     int *csock = (int*)lp;
  4.     int recu=0;
  5.     int bytecount=0;
  6.     int taille_buffer;   
  7.     if((bytecount = recv(*csock, &recu, sizeof(recu), MSG_WAITALL))== -1){
  8.         fprintf(stderr, "Erreur réception données %d\n", errno);
  9.        
  10.     }
  11.     printf("Taille recu: %d et en bytes %d \n", ntohl(recu),bytecount);
  12.    
  13.     taille_buffer = htohl(recu); //j'utilise htohl pour convertir le int que j'envoi depuis la tablette vers le serveur et le rendre lisible
  14.     char buffer[taille_buffer];
  15.    
  16.     memset(buffer, 0, sizeof(buffer));
  17.    
  18.     if((bytecount = recv(*csock, buffer, sizeof(buffer), MSG_WAITALL))== -1){
  19.         fprintf(stderr, "Erreur réception données %d\n", errno);
  20.        
  21.     }
  22.     printf("String recu: %s \n", buffer);
  23.  
  24.     write(0,"Fin du thread\n",15);
  25.     goto FINISH;
  26.    
  27.    
  28. FINISH:
  29.     free(csock);
  30.     return 0;
  31. }


Reply

Marsh Posté le 04-03-2012 à 14:12:36   

Reply

Marsh Posté le 05-03-2012 à 09:46:08    

Je pense que je vais essayer avec un malloc.

Reply

Marsh Posté le 05-03-2012 à 10:12:40    

Bonjour,
 

link953 a écrit :


Code :
  1. taille_buffer = htohl(recu); //j'utilise htohl pour convertir le int que j'envoi depuis la tablette vers le serveur et le rendre lisible




 
htohl ? Ca compile, ca ? J'imagine que tu voulais dire ntohl ?
Du côté de l'émission, tu as bien utilisé htonl sur ton int ?
 

link953 a écrit :


Code :
  1. goto FINISH;
  2.    
  3. FINISH:
  4.     free(csock);
  5.     return 0;
  6. }




 
Ton goto ne sert absolument à rien ! Il n’apparaît qu'en fin de boucle et renvoie sur l'instruction qui suit... Autant ne pas le mettre !
 
Bon, sinon, attention aussi avec les int ! La taille sur laquelle ils sont codés dépend du système:
système 64 bits => 8 octets
système 32 bits => 4 octets
Commence par t'assurer que tu envoies et reçois bien la taille sur le même nombre d'octets, sinon tu risques d'avoir des surprises.

Reply

Marsh Posté le 05-03-2012 à 13:34:53    

Salut merci de ta réponse,
 
Non c'est une erreur..j'utilise bien ntohl. En rechanche je n'utilise rien à l'émission. Sur la tablette Android donc en java l'envoi se fait avec WriteInt et c'est gérer dedans il me semble.
 
Le goto sert en faite mais il est impossible de le voir je n'ai pas mis tout le source pour ne pas trop prendre la tête aux personnes qui essaient de m'aider.
 
J'ai déjà fait les tests et la réception de la taille est nickel.
En fessant des tests je pense avoir trouvé la solution.
 
J'utilise un malloc :  
 
unsigned char buffer;
buffer = malloc(taille_buffer);
 
De cette façon je donne dynamiquement une taille au buffer.
 
Ensuite pour le recv qu'il ne ce vide pas...c'est juste que je suis un boulet.
Je lis 8 caractères et ensuite 0 et si je boucle pour afficher plusieurs fois le recv tout ce passe bien recv renvoi 0 et si j'affiche encore quelque chose c'est que mon buffer n'a pas été vidé tout simplement.
 
Voilà qu'en pensez-vous.

Reply

Marsh Posté le 05-03-2012 à 18:24:25    

Ton sizeof(buffer) est une constante qui te renvoie 8 (Sur une archi 64bits, car c'est la taille d'un pointeur qui est renvoyé, pas la taille de la zone allouée). Donc, si tu alloue une taille de "taille_buffer", bah, alors tente de lire "taille_buffer" octets avec recv et pas sizeof(buffer).
 
D'ailleurs, il serait sage de faire une boucle dans la réception. Il me semble que recv peut retourner avec moins de données qu'il n'a été envoyé (MTU, etc...). Bref un truc du genre:
 

Code :
  1. int expect, bytecount;
  2. char * p;
  3.  
  4. for (p = buffer, expect = taille_buffer; (bytecount = recv(*csock, p, expect, MSG_WAITALL)) > 0;
  5.     expect -= bytecount, p += bytecount);
  6.  
  7. if (bytecount < 0)
  8.     perror("recv" );
  9. else if (expect > 0)
  10.     fprintf(stderr, "bah, il manque des trucs: %d octets.", expect);


Disclaimeur: pas trop testé cela dit...
 
Edit: ouais, en fait non, la boucle est inutile.


Message édité par tpierron le 05-03-2012 à 18:27:33
Reply

Marsh Posté le 07-03-2012 à 10:25:15    

Salut!
 
Alors j'ai gratté de mon coté ( je n'aime pas attendre la solution sagement et j'ai écris ceci:  
 

Code :
  1. void* SocketHandler(void* lp)
  2. {
  3.     int *csock = (int*)lp;
  4.     int recu;
  5.     int bytecount;
  6.     int taille_buffer;
  7.     unsigned char *buffer;
  8.     unsigned char buffer_fichier[BUFSIZ];
  9.     int i;
  10.     FILE *fd;
  11.    
  12.     //Reception nom du fichier
  13.    
  14.     if((bytecount = recv(*csock, &recu, sizeof(recu), MSG_WAITALL))== -1) //premier recv qui permet de récuperer la taille de la chaine
  15.     {
  16.         fprintf(stderr, "Erreur réception données %d\n", errno);
  17.        
  18.     }
  19.     printf("Taille recu: %d et en bytes %d \n", ntohl(recu),bytecount);
  20.    
  21.     taille_buffer = ntohl(recu);
  22.     buffer=malloc(taille_buffer);
  23.    
  24.     if((bytecount = recv(*csock, buffer, taille_buffer, 0))== -1) //Deuxieme recv permettant de récuperer dans un buffer adequat la chaine de caractére
  25.     {
  26.         fprintf(stderr, "Erreur réception données %d\n", errno);
  27.        
  28.     }
  29.     printf("String recu: %s %d \n", buffer, bytecount);
  30.    
  31.     //Reception fichier
  32.    
  33.     if((fd=fopen(buffer,"wb" ))==NULL){  //ouverture du fichier avec la même chaine de caractére que celle envoyée
  34.         perror("Erreur" );
  35.         goto FINISH;
  36.     }
  37.     fseek(fd,0,SEEK_SET);
  38.     if((bytecount = recv(*csock, &recu, sizeof(recu), MSG_WAITALL))== -1) //Reception taille du fichier
  39.     {
  40.        
  41.         fprintf(stderr, "Erreur réception données %d\n", errno);
  42.        
  43.     }
  44.     printf("Taille recu: %d et en bytes %d \n", ntohl(recu),bytecount);
  45.     taille_buffer = ntohl(recu);
  46.    
  47.    
  48.     while((bytecount = recv(*csock, buffer_fichier,BUFSIZ, 0))>0) //reception du fichier et vidage du buffer dans le fichier ouvert précédemment.
  49.         fwrite(buffer_fichier,1,bytecount,fd);
  50.     fclose(fd);
  51.     write(0,"Fin du thread\n",15);
  52.     goto FINISH;
  53.    
  54.    
  55. FINISH:
  56.     free(csock);
  57.     return 0;
  58. }


 
Qu'en pensez vous?

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed