taille des buffers de reception d'un recv

taille des buffers de reception d'un recv - C++ - Programmation

Marsh Posté le 05-03-2003 à 16:13:13    

Lors de la fonction recv d'une socket, je me demandais ce qui se passerai si le serveur envoyais par exemple 300 char et que mon receive etait prevu pour en recevoir 250.
 
ex : send du server

Code :
  1. char* buffer = "123456789";
  2. send(s, buffer, sizeof(buffer),0);


 
ex : recv du client

Code :
  1. char* buffer;
  2. recv(s,buffer,5*sizeof(char),0);


Est il exacte que je ne vais recevoir que "12345"? Que va-t'il se passer?
 
et maintenant, si le serveur est :

Code :
  1. char* buffer = "12345";
  2. send(s, buffer, sizeof(buffer),0);


 
ex : recv du client

Code :
  1. char* buffer;
  2. recv(s,buffer,9*sizeof(char),0);


Je vais recevoir quoi dans mon buffer?


Message édité par polo021 le 05-03-2003 à 16:19:03
Reply

Marsh Posté le 05-03-2003 à 16:13:13   

Reply

Marsh Posté le 05-03-2003 à 16:52:37    

polo021 a écrit :

Lors de la fonction recv d'une socket, je me demandais ce qui se passerai si le serveur envoyais par exemple 300 char et que mon receive etait prevu pour en recevoir 250.


 
ex : send du server

Code :
  1. char* buffer = "123456789";
  2. send(s, buffer, sizeof(buffer),0);


 
Buffer est de type char* donc sizeof(buffer)=sizeof(char*)=4 (sur les pc) donc tu vas envoyer 4 caractères
 
Il fallait écrite :

Code :
  1. char* buffer = "123456789";
  2. send(s, buffer, (strlen(buffer)+1) * sizeof(char),0);


 
 
ex : recv du client

Code :
  1. char* buffer;
  2. recv(s,buffer,5*sizeof(char),0);


Est il exacte que je ne vais recevoir que "12345"? Que va-t'il se passer?
 
Ici, recv va écrire à l'addresse mémoire pointée par buffer. Or buffer n'est pas inialisé et pointe donc n'importe où. Il y a de grandes chances que ça plante.
Correction :

Code :
  1. char buffer[256];
  2. recv(s,(void*)buffer,5*sizeof(char),0);


 
Ici, les 5 premiers caractères de buffer serons "12345" suivit ne n'importe quoi (recv n'écrira que dans les 5 premiers caractère)
Si tu veux afficher la chaine, n'oublie pas de rajouter \0 à la fin : buffer[5]='\0';
 
Si tu fais un autre recv juste après, tu recevras la fin de ta chaine : 6789.
 
 
et maintenant, si le serveur est :

Code :
  1. char* buffer = "12345";
  2. send(s, buffer, (strlen(buffer)+1) *sizeof(char),0);


 
ex : recv du client

Code :
  1. char buffer[256];
  2. recv(s,buffer,9*sizeof(char),0);


Je vais recevoir quoi dans mon buffer?
 
La, je ne suis pas sur mais je crois que cela dépend de ta socket, si elle est bloquante ou non.
Si elle est bloquante recv attendra un autre send pour remplir 9 caractère du buffer.
Si elle est non bloquante, je crois que recv te rempli juste 5 caractères et te retoune 5.
Mais le mieux est de lire le manuel de send et recv !!
 
 
 

Reply

Marsh Posté le 05-03-2003 à 20:16:49    

Dans le cas d'une connexion TCP, il n'y a aucune notion de paquet. L'un des PC envoie une suite d'octets, et l'autre reçoit les même octets, dans l'ordre, mais pas forcément avec les même limites.
Par exemple, si tu envoies 20 octets, puis 10, le client peut très bien recevoir 5 octets, puis 12, puis 13. Le recv() peut également retourner, même s'il n'a pas rempli complètement le buffer.

Reply

Marsh Posté le 06-03-2003 à 12:47:50    

Est-ce que ceci est une bonne solution, ou je rate qqchose :
 
on définit une struct ki sera la meme dans le client et le
serveur, par ex :
 

Code :
  1. #define MAX 1024
  2. typedef struct s_Bordel
  3. {
  4.     UINT Size;
  5.     char Data[MAX - 4]; // -4 fote a l'UINT
  6. } t_Bordel;


 
puis dans le serveur on fait des send de cette facon :
 

Code :
  1. t_Bordel Bordel;
  2. string str = "trucs a envoyer";
  3. CopyMemory(Bordel.Data, str.c_str(), str.length());
  4. Bordel.Size = 4 + str.length();
  5. send(s, (char *)&Bordel, Bordel.Size, 0);


 
pour le client, tout le truc chiant c qu'il faut s'attendre
a recevoir des "bouts de paquets". on fait donc des recv() tant
qu'on a pas recu le nb d'octets indiqués au debut de la struct.
 
ca ressemblerait ptet un peu a ca :
 

Code :
  1. t_Bordel Bordel;
  2. int BytesReceived = recv(s, (char*)&Bordel, MAX, 0);


 
Apres on a Bordel.Size ki vaut la taille totale du paquet,
il suffit donc de tester le retour du recv, s'il est plus
petit que Bordel.Size c'est qu'on a pas recu le paquet en
entier, il faut donc refaire un recv() et convaluer le
résultat...
 
mais comme l'a dit Bebert, les résultats sont assez aléatoires,
on recoit souvent des bouts de paquets, voire meme plusieurs
paquets convalués en 1 seul...
 
j'ai fait qq tests chez moi, ca avait l'air de fonctionner
plutot bien, mais si des experts pouvaient me conseiller
autre chose, ils sont les bienvenus...

Reply

Marsh Posté le 06-03-2003 à 13:35:53    

voila la solution que j'qi adoptee :  

Code :
  1. char* msg;
  2. if (recv(s,msg, 255*sizeof(msg), 0 )== SOCKET_ERROR )
  3. {
  4.            erreur
  5. }
  6. else
  7. {
  8. AfxMessageBox((CString)msg);
  9. }


 
et ca a l'air de bien fonctionner.
Par contre ce qui ne fonctionne pas c'est  

Code :
  1. char msg[255];
  2. if (recv(s,msg, sizeof(msg), 0 )== SOCKET_ERROR )
  3. {
  4.            erreur
  5. }
  6. else
  7. {
  8. AfxMessageBox((CString)msg);
  9. }


car a l'affichage j'ai des caracteres illegaux a la fin de mon message.
Pensez vous que la premiere solution est une solution fiable si on considere que le serveur envoie toujours des messages de 255 caracteres?

Reply

Marsh Posté le 06-03-2003 à 14:00:09    

les 2 solutions sont identiques (les recv sont tous les 2 de 255), a la difference que pour le 1er cas si tu ne malloc pas le 'char *msg' ca risque de seg-folter.
 
ca devrait marcher dans les 2 cas, le seul pb peut venir du '\0' de fin de chaine : si tu envoies "12345" et que tu fais send(s, "12345", 5, 0), lors de ton recv tu n'auras pas le '\0' pour indiquer la fin de chaine. il faut donc faire un send(s, "12345\0", 6, 0) et ca devrait marcher mieux.

Reply

Marsh Posté le 06-03-2003 à 19:16:28    

Konar a écrit :

Est-ce que ceci est une bonne solution, ou je rate qqchose :
 
on définit une struct ki sera la meme dans le client et le
serveur, par ex :
 

Code :
  1. #define MAX 1024
  2. typedef struct s_Bordel
  3. {
  4.     UINT Size;
  5.     char Data[MAX - 4]; // -4 fote a l'UINT
  6. } t_Bordel;


 
puis dans le serveur on fait des send de cette facon :
 

Code :
  1. t_Bordel Bordel;
  2. string str = "trucs a envoyer";
  3. CopyMemory(Bordel.Data, str.c_str(), str.length());
  4. Bordel.Size = 4 + str.length();
  5. send(s, (char *)&Bordel, Bordel.Size, 0);


 
pour le client, tout le truc chiant c qu'il faut s'attendre
a recevoir des "bouts de paquets". on fait donc des recv() tant
qu'on a pas recu le nb d'octets indiqués au debut de la struct.
 
ca ressemblerait ptet un peu a ca :
 

Code :
  1. t_Bordel Bordel;
  2. int BytesReceived = recv(s, (char*)&Bordel, MAX, 0);


 
Apres on a Bordel.Size ki vaut la taille totale du paquet,
il suffit donc de tester le retour du recv, s'il est plus
petit que Bordel.Size c'est qu'on a pas recu le paquet en
entier, il faut donc refaire un recv() et convaluer le
résultat...
 
mais comme l'a dit Bebert, les résultats sont assez aléatoires,
on recoit souvent des bouts de paquets, voire meme plusieurs
paquets convalués en 1 seul...
 
j'ai fait qq tests chez moi, ca avait l'air de fonctionner
plutot bien, mais si des experts pouvaient me conseiller
autre chose, ils sont les bienvenus...

Ca va pas :o  
Tu envoie des données d'une taille variable (<= MAX), et tu attends jusqu'à recevoir MAX octets. Tu prends le risque de rester indéfiniment en attente de données qui n'arriveront jamais.
Pour la réception, il me parait préférable de lire le UINT seul, puis de lire le nombre d'octets correspondants.
 
Pour le problème du '\0' terminal, c'est à toi de voir. Soit tu l'envoie, soit tu l'envoie pas, mais il faut que l'émetteur et le récepteur soient d'accord.


Message édité par mrbebert le 06-03-2003 à 19:20:08
Reply

Marsh Posté le 07-03-2003 à 12:27:06    

mrBebert a écrit :

Ca va pas :o  
Tu envoie des données d'une taille variable (<= MAX), et tu attends jusqu'à recevoir MAX octets. Tu prends le risque de rester indéfiniment en attente de données qui n'arriveront jamais.
Pour la réception, il me parait préférable de lire le UINT seul, puis de lire le nombre d'octets correspondants.
 
Pour le problème du '\0' terminal, c'est à toi de voir. Soit tu l'envoie, soit tu l'envoie pas, mais il faut que l'émetteur et le récepteur soient d'accord.


 
pas tout a fait : en fait dans le recv, le MAX indique juste la taille maximale pouvant etre recue, et non la taille qui DOIT etre recue. recv retournera le nb d'octets qu'il a mis dans le buffer.
 
le 3eme parametre du recv (MAX) indique juste la taille maximale du buffer. D'apres les man : "If the datagram or message is larger than the buffer supplied, the buffer is filled with the first part of the datagram, and recv generates the error WSAEMSGSIZE."
 
pour le '\0', c juste pour les gens ki envoient des phrases, et dans leur cas il suffit de faire un ZeroMemory sur leur buffer.
(moi j'envoie du binaire, donc j'ai pas ce pb).
 
par contre pour ta solution de faire un recv de 4 pour recevoir juste l'UINT, puis un autre recv avec la taille correspondante, c pas con, je vais tester ca...
 
a+

Reply

Marsh Posté le 07-03-2003 à 19:21:38    

Konar a écrit :


 
pas tout a fait : en fait dans le recv, le MAX indique juste la taille maximale pouvant etre recue, et non la taille qui DOIT etre recue. recv retournera le nb d'octets qu'il a mis dans le buffer.
 
le 3eme parametre du recv (MAX) indique juste la taille maximale du buffer. D'apres les man : "If the datagram or message is larger than the buffer supplied, the buffer is filled with the first part of the datagram, and recv generates the error WSAEMSGSIZE."
 
pour le '\0', c juste pour les gens ki envoient des phrases, et dans leur cas il suffit de faire un ZeroMemory sur leur buffer.
(moi j'envoie du binaire, donc j'ai pas ce pb).
 
par contre pour ta solution de faire un recv de 4 pour recevoir juste l'UINT, puis un autre recv avec la taille correspondante, c pas con, je vais tester ca...
a+

Ca ne correspond pas plutot à de l'UDP :heink:  
 
Je parle du cas où les données reçues sont de taille < MAX. Lorsque ta socket est bloquante, elle va attendre d'avoir des données en plus. Alors qu'aucune autre donnée n'arrivera.
Bien sur, on peut supposer qu'au bout d'un moment, elle se terminera quand même. Mais ce n'est pas garantit.
Tu prends donc le risque d'avoir un programme qui reste bloqué à attendre des données qui n'arriveront jamais :/

Reply

Sujets relatifs:

Leave a Replay

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