Socket, realloc et pixel

Résolu
ZenShu -  
 Utilisateur anonyme -
Bonjour,

Je suis entrain de faire un petit programme avec un serveur et un client. J'ai donc pris exemple sur le tuto disponible sur le site en le modifiant mais je me heurte à quelques problèmes.

J'ai un client qui envoie tout d'abord la taille de ce que je vais envoyé et ensuite le message en lui même: un tableau de char de 320*240(76800) cases en 1D, chaque cases correspondant à la valeur d'un pixel. De ce côté pas de problème à déclarer.

Du côté du serveur, ça se gâte. Je récupère la taille du message. J'alloue ensuite dynamiquement un tableau "image" de cette taille. Et maintenant je récupère le message en lui même. Vu qu'avec le protocole tcp je suis limité à 65536 octets par réception je suis obligé de le faire en plusieurs fois. J'écris donc dans mon buffer (alloué dynamiquement avec une taille de 65536) une première fois et le concatène avec "image" qui est pour l'instant vide. Je réitère l'opération en ayant ré alloué la taille de mon buffer pour qu'elle corresponde à ce qu'il me reste à lire soit normalement 11264 octets. Je devrais donc me retrouver avec mon tableau de pixel correctement recomposé.

Premier problème:
Pour tester mon application je commence par envoyer un tableau de '1'. Je vois que la réception se fait correctement. J'affiche la valeur des cases et celles-ci est bonne. Mais lorsque j'affiche la longueur de ma chaîne de caractère je me retrouve avec 6 octets de plus soit 76806 au lieu de 76800. Ils apparaissent après la ré allocation de la mémoire de mon buffer de lecture et je ne sais pas du tout pourquoi.

Second problème:
Je souhaite envoyer la valeur des pixels d'une image. Celle-ci étant quelquefois égale à 0, cela me pose des problèmes de lecture. En effet la fonction recv doit supposer voir un EOF et s'arrète. Je ne sais pas comment éviter ce problème et lui dire de s'occuper de lire seulement le nombre d'octets indiqué en paramètre. L'envoie à l'air de se dérouler correctement quant à lui.

Voici la partie de mon code qui semble poser problème:

if((nb_lu=recv(csock,&taille_img, sizeof(int),0))!= SOCKET_ERROR)
{
	printf("taille du message reçu: %d \n", taille_img);
	image=realloc(image,(taille_img)*sizeof(char));
	if(image==NULL)
	{
		printf("problème allocation");
		exit(EXIT_SUCCESS);
	}
	else printf("allocation réussie du buffer image\n");
						
	reste=taille_img;
	if(taille_img>MAX_BUF)
	{
		taille=MAX_BUF;
		printf("taille_img = %d et taille = %d", taille_img, taille);
	}	
}
else printf("le message n'a pas ete reçu\n");

/*Recuperation du message en lui-meme*/
do
{	
if((nb_lu=recv(csock,buffer, taille*sizeof(char),0))!= SOCKET_ERROR)
{
	printf("\n************message reçu************\n");
	printf("\nlecture de %d octets\n", nb_lu);

	reste-=nb_lu;
	taille=reste;
	if(taille>MAX_BUF)
	{
		taille=MAX_BUF;
	}
	snprintf(image+dec,taille_img, "%s",buffer);
							
	printf("longueur du buffer %d\n", strlen(buffer));
	printf("longueur du buffer image %d\n", strlen(image));
	printf("decalage = %d\n",dec);
	dec+=nb_lu;
	printf("taille= %d\n", taille);	
	}
	else printf("le message n'a pas ete reçu\n");	
						
	if(!taille) taille=MAX_BUF;					
						
	buffer=realloc(buffer,taille*sizeof(char));
	if(image==NULL)
	{
		printf("problème allocation");
		exit(EXIT_SUCCESS);
	}
	else printf("reallocation réussie du buffer: taille= %d \n", taille);
}
while(reste);	




Et voici la sortie obtenue avec un tableau de '1':

taille du message reçu: 76800
allocation réussie du buffer image
taille_img = 76800 et taille = 65536
************message reçu************

lecture de 65536 octets
longueur du buffer 65536
longueur du buffer image 65536
decalage = 0
taille= 11264
reallocation réussie du buffer: taille= 11264
longueur du buffer apres realloc 11270

************message reçu************

lecture de 11264 octets
longueur du buffer 11270
longueur du buffer image 76806
decalage = 65536
taille= 0
reallocation réussie du buffer: taille= 65536


J'ai fini :) bon je sais pas si il y aura beaucoup de courageux pour lire ça mais j'espere.
Merci

5 réponses

Utilisateur anonyme
 
En fait moi j'ai déjà eu le cas. Avec un malloc mal fait ou encore une erreur de typage. Un char = 1octet un int = 4o ...

Vérifies tes mallocs, affiche la valeur que tu alloues !

Je préfères utiliser free() et malloc() plutôt que realloc.
0
ZenShu
 
ok je vais déjà tester ça.
0
ZenShu
 
Bon j'ai testé et je retombe sur le même problème. Je vais garder qd mm le système free puis malloc qui à l'air plus stable pour les gros tableaux



do
{
if((nb_lu=recv(csock,buffer, MAX_BUF*sizeof(char),MSG_PEEK))!= SOCKET_ERROR)
{
free(buffer);
printf("\n************message reçu************\n");
printf("\nlecture de %d octets\n", nb_lu);
buffer=malloc(nb_lu*sizeof(char));
if(buffer==NULL)
{
perror("problème allocation");
exit(EXIT_FAILURE);
}
else printf("allocation réussie du buffer: taille= %d \n", nb_lu);

if((nb_lu=recv(csock,buffer, nb_lu*sizeof(char),0))!= SOCKET_ERROR)
{
reste-=nb_lu;
printf("longueur du buffer %d\n", strlen(buffer));
snprintf(image+dec,taille_img, "%s",buffer);
printf("decalage = %d\n",dec);
printf("longueur de l'image %d\n", strlen(image));
dec+=nb_lu;
}
else
{
perror("le message n'a pas ete reçu 2\n");
exit(EXIT_FAILURE);
}
}
else
{
perror("le message n'a pas ete reçu 3\n");
exit(EXIT_FAILURE);
}

}
while(reste);



et voila ma sortie.

lecture de 11264 octets
allocation réussie du buffer: taille= 11264
longueur du buffer 11270
decalage = 65536
longueur de l'image 76806


je lis bien 11264 octets, j'alloue mon tableau en conséquence et après la fonction recv() je me retrouve avec 6 octets supplémentaire! help
0
Utilisateur anonyme
 
Pour être plus propre, quand tu fais ton free() il faut vérifier que le buffer est non null

if(buffer!=NULL) //ou if(buffer)
  free(buffer);
  buffer=NULL; //pointe nul part
}


Ensuite un malloc il faut le cast

Exemple
char *buffer;
buffer=(char*)malloc(sizeof(char)*1024);


Préfère sizeof(buffer) plutôt que strlen(buffer).

La ligne else printf("allocation réussie du buffer: taille= %d \n", nb_lu); ne met pas nb_lu mais plutôt la vrai taille soit sizeof(buffer).

idem ici printf("longueur du buffer %d\n", strlen(buffer)); => sizeof(buffer)

Et reposte les retours
0
ZenShu
 
Merci, j'avais une incohérence dans mon code. Maintenant ça fonctionne mais je ne sais pas pourquoi.

 do
{	
	if((nb_lu=recv(csock,tmp, MAX_BUF*sizeof(char),MSG_PEEK))!= SOCKET_ERROR)
	{
			printf("\n************message reçu************\n");
			printf("\nlecture de %d octets\n", nb_lu);

			/*if(buffer!=NULL)
			{
				free(buffer);
				buffer=NULL;
			}*/

			buffer=(char *)malloc(nb_lu*sizeof(char));
			if(buffer==NULL)
			{
					perror("problème allocation");
					exit(EXIT_FAILURE);
			}
			else printf("allocation réussie du buffer: taille= %d \n", nb_lu);

			if((nb_lu=recv(csock,buffer, nb_lu*sizeof(char),0))!= SOCKET_ERROR)
			{
					reste-=nb_lu;
					printf("longueur du buffer %d\n", strlen(buffer));
					snprintf(image+dec,taille_img, "%s",buffer);
					printf("decalage = %d\n",dec);
					printf("longueur de l'image %d\n", strlen(image));
					printf("longueur du buffer %d\n", strlen(buffer));
					dec+=nb_lu;
			}
			else
			{
				perror("le message n'a pas ete reçu 2\n");	
				exit(EXIT_FAILURE);
			}
	}
	else
	{
		perror("le message n'a pas ete reçu 3\n");	
		exit(EXIT_FAILURE);
	}
}
while(reste);	


J'ai mis un autre pointeur de char en paramètre dans mon premier recv() car au final mon buffer n'avait plus la taille adéquate et faisait planter mon programme. Par contre lorsque je souhaite libérer la mémoire de mon buffer avec ta méthode mon programme plante au deuxième appel à l'endroit du free(buffer)!

erreur:
*** glibc detected *** ./serveur: free(): invalid next size (normal): 0x0806dc18 ***
...


Lorsque je ne le mets pas ça marche sans problème mais je ne sais pas ce que donne la gestion de la mémoire dans ce cas là, on peut pas dire que ça soit sérieux.

Par contre, pour le reste je vois dans beaucoup de forum ou des cours qu'il est inutile de cast les mallocs... Je ne m'y connais pas assez pour savoir ce qu'il faut ou ne pas faire donc je reste dans le flou pour ça.

Ensuite le sizeof() ne me permet pas d'afficher la longueur de ma chaîne de caractère mais juste la taille qu'occupe un pointeur de char, c'est à dire 4. Ce qui n'est pas trop mon but.
0
Utilisateur anonyme
 
Effectivement j'ai dis des bêtises sur le sizeof() il renvoit 4 sur les PC. En fait même strlen est faux.

Si tu alloues une chaine de 10 par exemple char *buf=(char*)malloc(sizeof(char)*10);

Ensuite dans une boucle tu remplis jusqu'à 10 for(i=0; i<10; i++) buf[i] = 'a';

strlen(buf) renvoie 10

Or si tu fais for(i=0; i<8; i++) buf[i] = 'a';

strlen(buf) renvoie 8 et non 10 malgré le malloc de 10.

C'est bien ta variable nb_lu qu'il faut conserver car elle seule a la bonne valeur.

Pour l'histoire du Free, tout simplement parce que tu ne dois pas allouer la mémoire pour cette variable

Cet exemple ne marche pas, car buffer n'est pas null, donc il entre dans le if et ne peut faire un free car pas de mémoire allouée.
char *buffer;
if(buffer)
{
  free(buffer);
  buffer=NULL;
}


Pour quelque chose de propore il faut faire :
(sans malloc)
char *buffer = NULL;
if(buffer)
{
  free(buffer);
  buffer=NULL;
}


(avec malloc)

char *buffer = NULL;
buffer = (char*)malloc(sizeof(char)*10);
if(buffer)
{
  free(buffer);
  buffer=NULL;
}


Pour le cast, je préfère le mettre et être sur qu'un jour si j'ai une belle erreur le problème vienne de là. Dans ce cas, pour un char, sizeof(char) est toujours égal à 1 donc il est inutile. Mais on le met quand même ! Tout dépend du compilateur.

En manipulant correctement free(variable) et variable= NULL , normalement tu n'as pas besoin d'utiliser une autre variable.

0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
ZenShu
 
Ok c'est tout bon :) merci
Je préfère laisse le sizeof(char) car c'est pour un processeur 8 bits même si il y a peu de chance que la valeur soit différente, on sait jamais.
0
Utilisateur anonyme
 
Exactement !! C'est pour ça que je laisse toujours les Cast, pour pas être embêté par un compilateur un peu chiant !

Si c'est bon tu peux cocher résolu ^^
0