IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Réseau C Discussion :

fonction send() recv() et fragmentation des paquets TCP


Sujet :

Réseau C

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 8
    Points : 3
    Points
    3
    Par défaut fonction send() recv() et fragmentation des paquets TCP
    Bonsoir tous le monde,
    je programme actuellement un client et un serveur dans le but de créer un chat.

    Coté serveur (bout de code faisant parti d'une fonction, elle meme lancer via plusieurs thread):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
    		while(1){
     
    //Pause de 3 secondes entre chaque envoi
    			Sleep(3000); 
    			//Envoi de la liste des peers 
    			send(client, a->liste.peerlistToString().c_str(), a->liste.peerlistToString().size()+1, 0);  
    		}
    Coté client :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    while(1){
     
    		//Reception de la liste des peers
    		recv(sock, buffer, sizeof(buffer), 0);
     
    		//Pause de 1 seconde entre chaque "rafraichissement de console"
    		Sleep(1000);
    		system("CLS");
     
    		//Affichage de la liste
    		cout<<"Connected peer(s) : ";
    		cout<<(string)buffer<<endl;
     
     
    	}
    Ma question : le faite que j'attende 3 secondes entre chaque send() va-t-il empêcher une éventuelle fragmentation des paquets TCP ?

    car si j'envoie genre 1000 caractères d'un coup, mon code coté client avec le recv() ne vas plus fonctionner correctement,
    il faudrait donc que je recupere chaque octet un par un via un do while ?

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 369
    Points
    50 369
    Par défaut
    En TCP, ce n'est pas la bonne manière de faire.

    Soit ton protocole sais se synchroniser tout seul (toutes les trames applicatives on la même taille) et il n'y a pas de problème.

    Soit les trames on des tailles différentes et il faut que tu aides le récepteur à se synchroniser.

    Pour cela, en général, la première information envoyée par l'émetteur est la taille de la trame (sur 2 ou 4 octets binaires ou sur 5 ou 6 octets texte clair suivant ton protocole) suivi de la trame elle même. Peut importe le format de la taille mais il doit être fixe et connu des 2 parties.

    Ainsi, le récepteur lit d'abord la taille de la trame fait éventuellement une allocation mémoire pour recevoir la trame et fait la réception de la trame.

    Ainsi, tu n'a plus à te soucier de la fragmentation, cela reste un problème TCP uniquement.

    Si tu veux envoyer 15000 octets (cela va fractionner), l'emetteur fait
    • send(15000)
    • send (buffer[15000])


    et le recepteur attend la taille et ensuite recoit tous les octets

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    Si tu veux envoyer 15000 octets (cela va fractionner), l'emetteur fait

    * send(10000)
    * send (buffer[15000])
    ce n'est pas plutot cela :

    * send(15000) > on envoi l'information sur le nombre d'octet de la trame
    * send (buffer[15000]) > on envoi ensuite la trame en question


    vrai ? ou c'est moi qui mal compris ?

  4. #4
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 369
    Points
    50 369
    Par défaut
    Citation Envoyé par nice2cu Voir le message
    * send(15000) > on envoi l'information sur le nombre d'octet de la trame
    * send (buffer[15000]) > on envoi ensuite la trame en question
    Vrai , c'est moi qui ait mal écrit

    Message initial modifié

  5. #5
    Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    okay merci pour l'aide.

    je vais m'occuper de tous ça au plus vite.

  6. #6
    Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    Bon j'ai un probleme qui est apparu depuis, je m'explique :

    Mon programme serveur en console,
    a une classe CPeerlist qui contient des objet CPeer (string pseudo, string ip).

    Ce serveur s'occupe de lancer 2 threads,
    qui vont permettre à 2 clients de se connecter et de se voir connecter.
    Pour cela il faut donc que je renvoi aux 2 clients, la liste des clients connecté c'est à dire eux même.

    Le soucis c'est que j'ai beau envoyer des send() de la CPeerlist mise à jour par l'un ou l'autre thread,
    le client ne reçoit pas la liste mise à jour regulieremment par la boucle while !!!

    aidez moi serieux je ne comprend pas pourquoi ça ne marche pas ...

    voici mon code coté serveur, la fonction suivante est lancé à l'aide d'un pthread :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
     
    void *newClient(void* data)
    {
    	donnees* a = (donnees*)data;
     
    	//Socket client
    	SOCKET client; 
     
    	//Definition socket client
    	SOCKADDR_IN csin; 
     
    	int sinsize = sizeof(csin);
        if((client = accept(a->server, (SOCKADDR *)&csin, &sinsize)) != INVALID_SOCKET)
        {
    		//Reception taille du pseudo
    		int recvValue = 0;
    		recv(client, (char *)&recvValue, sizeof(recvValue), 0);
    		recvValue = ntohl(recvValue);
     
    		//Reception du pseudo
    		char *buffer = new char[recvValue];
    		recv(client, buffer, recvValue, 0);
     
    		//Ajout du peer dans la liste (section critique)
    		CPeer peer(string(buffer), (string)inet_ntoa(csin.sin_addr));
    		a->liste.add(peer);
     
    		//On supprime le buffer en memoire
    		delete[] buffer;
     
    		while(1){
     
    			//Envoi de la taille du buffer
    			int sendValue = htonl(a->liste.peerlistToString().size()+1);
    			send(client, (const char*)&sendValue, sizeof(sendValue), 0);
     
    			//Envoi du buffer (liste des peers)
    			send(client, a->liste.peerlistToString().c_str(), a->liste.peerlistToString().size()+1, 0);  
    		}
    	}
    	return NULL;
    }
    La structure de données mis en paramettre pour la fonction du dessus :
    typedef struct {
    SOCKET server; //socket d'ecoute
    SOCKADDR_IN sin; //definition socket d'ecoute
    CPeerlist liste; //liste de CPeer
    }donnees;
    Le code coté client :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    	//Envoi de la taille du pseudo
    	int sendValue = htonl(nickname.size()+1);
    	send(sock, (const char*)&sendValue, sizeof(sendValue), 0);
     
    	//Envoi du pseudo
    	send(sock, nickname.c_str(), nickname.size()+1, 0);
     
    	while(1){
     
    		//Reception de la taille du buffer
    		int recvValue = 0; //nb de caracteres + '\0'
    		int ret = 0; //nb d'octets reçu (nous envoyons un int codé sur 32 bits soit 4 octets)
    		ret = recv(sock, (char*)&recvValue, sizeof(recvValue), 0);
    		recvValue = ntohl(recvValue);
     
     
    		//Reception du buffer (liste des peers)
    		char *buffer = new char[recvValue];
    		recv(sock, buffer, recvValue, 0);
     
     
    		//"rafraichissement de console" toute les secondes
    		Sleep(1000);
    		system("CLS");
     
    		//Affichage de la liste
    		cout<<"Number of characters received: "<<recvValue<<endl;
    		cout<<"Number of bytes received: "<<ret<<endl;
    		cout<<"Connected peer(s) : "<<(string)buffer<<endl;
     
    		//On supprime le buffer en memoire
    		delete[] buffer;
     
     
     
    	}

  7. #7
    Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    bon je viens de trouver la solution mais je comprend pas pourquoi cela marche :

    Coté serveur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    while(1){
     
    			Sleep(1000); //LA SOLUTION FAIRE UNE PAUSE DE 1 SECONDE !!!
     
    			//Envoi de la taille du buffer
    			int sendValue = htonl(a->liste.peerlistToString().size()+1);
    			send(client, (const char*)&sendValue, sizeof(sendValue), 0);
     
    			//Envoi du buffer (liste des peers)
    			send(client, a->liste.peerlistToString().c_str(), a->liste.peerlistToString().size()+1, 0);  
    		}
    	}
    faut t-il synchroniser le client et le serveur enfin chaque thread ?

  8. #8
    Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    UP ! pourquoi suis je obligé de mettre une tempo (sleep()) entre chaque serie de send() vers le client qui lui meme à une serie de recv() dans une boucle infini ????

  9. #9
    Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 8
    Points : 3
    Points
    3
    Par défaut
    bon j'ai trouvé le probleme grace à l'aide d'une personne du SDZ.

    le probleme c'est que si je ne met pas de Sleep suiffisamment long, le recv() peut ne pas avoir le temps de remplir entièrement le buffer de reception.

    du coup l'ideal est de faire une boucle qui tant que le recv n'a pas reçu le nbre d'octets attendu, on refait un recv...

    bref il y a un commentaire interressant (le dernier) et tres important dans la doc msdn :
    http://msdn.microsoft.com/en-us/libr...8VS.85%29.aspx

Discussions similaires

  1. Echange des paquets TCP
    Par passkok dans le forum Entrée/Sortie
    Réponses: 6
    Dernier message: 15/04/2009, 01h14
  2. Taille des paquets en TCP
    Par coyotte507 dans le forum Développement
    Réponses: 2
    Dernier message: 26/08/2008, 13h57
  3. [TCP] Taille de buffer, et fonction send()
    Par phraides dans le forum Développement
    Réponses: 4
    Dernier message: 03/06/2007, 15h45
  4. Réponses: 4
    Dernier message: 23/05/2007, 10h12
  5. Question sur les fonctions "send()" et "recv(
    Par damien99 dans le forum MFC
    Réponses: 6
    Dernier message: 10/02/2006, 21h47

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo