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

C++ Discussion :

[TCP] Packet non reçu lors d'un transfert de fichier en TCP


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut [TCP] Packet non reçu lors d'un transfert de fichier en TCP
    Bonjour,

    Je suis en train d developper une petite application permettant a un client de se connecter a un serveur puis de recuperer des fichiers. J'utilise le protocole TCP. Un probleme intervient lorsque j'essaie de transferer des fichiers de plusieur ko.
    Le serveur effectue bien l'envoi de tous les octets du fichiers (la somme des retours du send() est égale a la taille du fichier) mais le client reste bloqué sur un recv() car a un moment dans la boucle while, la valeur de retour de recv n'est pas la taille du tampon (256, 128 ou autres) mais une valeur tres faible, generalement 6.

    Voila un bout de code montrant comment se fait l'envoi coté serveur et la reception 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
     
    //********Coté serveur**************
    				long tailleFichier = getSize(nom);  //renvoie la taille du fichier nom
    				char msg[256];
    				sprintf(msg, "%d", tailleFichier);
    				int lgMsg = strlen(msg);
    				int snd = send(descBr, msg, lgMsg, 0); //on envoie la taille du fichier au client
     
    				//Si le fichier existe on l'expédie au client
    				if (tailleFichier != -1)
    				{
    					//Ouverture du fichier a envoyer
    					size_t s = nom.size() + 1;
    					char * nomFichier = new char[ s ];
    					strncpy( nomFichier, nom.c_str(), s );
    					FILE* fichier;
    					if((fichier=fopen(nomFichier, "rb")) == NULL)
    					{
    						cout << "Probleme lors de l'ouverture du fichier." << endl;
    					}
     
    					//Expedition du fichier
    					cout << "Debut de l'expedition du fichier" << endl;
    					int octetsEnvoyes = 0;
    					int octetsLus;
    					char buffer [256];
    					while(octetsEnvoyes != tailleFichier)
    					{
    						octetsLus=fread(buffer, 1, 256, fichier);
    						snd = send(descBr, buffer, octetsLus, 0);
    						octetsEnvoyes = octetsEnvoyes + snd;
    				         }
     
    					//On fini par fermer le fichier
    					fclose(fichier);
    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
     
    //*************Coté client****************
            char  tamponReception [256];
    	int lgReception = sizeof(tamponReception);
    	int retourRecv = recv (descLocale, tamponReception, lgReception, 0); //recption de la taille du fichier
    	tamponReception[lgReception] = '\0';
    	long tailleFichier= atoi (tamponReception);
     
    	//On crée et ouvre le fichier que va nous envoyer le serveur
    	FILE* fichier;
    	if((fichier=fopen("./monFic", "wb")) == NULL)
    	{
    		cout << "impossible de creer le fichier" << endl;
    	}
    	long octetsRecus = 0;
    	while(octetsRecus != tailleFichier)
    	{
    			retourRecv=recv(descLocale,tamponReception, 256, 0);
    			octetsRecus = octetsRecus + retourRecv;
    			fwrite(tamponReception, 1, retourRecv, fichier);
    	}
    	fclose(fichier);
    Dès que je transfere des fichiers de quelques ko un des buffers n'est rempli qu'a 5 ou 6 char coté client en plein milieur de la transmission alors qu'il devrait etre de 256. J'ai testé avec des valeur beaucoup plus faible de l'ordre de 16 ou 32 et ça plante toujours dès que le fichier est trop gros :/
    Quelques remarques bizarre :
    - si je met la taille de mon buffer à une valeur <= 7 là c'est ok meme pour des fichiers plus gros (comme un mp3 de qques MO) mais c'est horriblement long;
    - lorsque je teste sur des petits fichiers (sources de mon prog par exemple), ça marche tout le temps meme avec des buffers importants
    - Pour un meme fichier faisant planter, le buffer de taille anormalement rempli est toujours de la meme taille (5 ou 6)
    Je suis dessus depuis hier et rien a faire : j'etais persuader qu'en tcp il n'y avait pas de perte de donnée :/

  2. #2
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    Le probleme pourrait il venir d'ailleurs ? pour la lecture (coté serveur) et ecriture (coté client du fichier j'ai pris comme base l'exemple de copie de fichier present dans la FAQ C et cela marche bien. Bref si quelqu'un a une idée ou une solution je crois bien que je vais lui ériger une statut a son effigie et un culte pendant de longues années

  3. #3
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    Apparemment le transfert marche si j'ai le serveur et le client sur deux machines distinctes mais plante lorsque les deux cohabitent sur la meme machine

  4. #4
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    up

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Quelle est la taille de buffer renvoyée quand tu fais un getsockopt() ?
    Et je dis bien get et non set...

    PS: Fais le getsockopt des deux cotés, bien sur...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    je teste ça et je le poste dans quelques minutes

  7. #7
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    Voila je viens de tester et j'obtiens une valeur etrange : coté client tout va bien, getsockopt me renvoit 0 et l'affichage de optval (4 eme param) me donne 87680 mais coté serveur getopt me renvoit -1 :/
    Je precise que l'appel a getsockopt est effectué coté serveur apres l'appel a accept et donc apres recuperation du descripteur du socket
    edit : un petit perror() m'affiche invalid argument
    edit 2 : voici l'appel que j'effectue coté client et coté serveur une fois que la connexion est etablie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    int optval;
    socklen_t optlen;
    cout << getsockopt(desBR, SOL_SOCKET,SO_RCVBUF, &optval, &optlen) << endl << "Taille du tampon : " << optval <<endl;;

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    1°) Ben dis-donc, 87680, c'est bizarre comme taille: Non seulement c'est un peu gros, mais en plus, binairement parlant, c'est un peu gros...
    2°) Bizarre aussi que ça foire...


    --> Tu peux poster le code de tes deux getsockopt() ?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    voila c posté
    J'obtiens les meme resultats pour SO_SNDBUF

  10. #10
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    1) Optlen doit être initialisé à sizeof(optval) avant l'appel à getsockopt()...
    2) Juste pour être sur: Tu affiches bien optval après avoir affiché le retour de getsockopt() ?
    3) Fais-le pour SO_RCVBUF et pour SO_SNDBUF, sur les deux programmes (4 getsockopt() au total, quoi)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  11. #11
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    J'y vais je te dis ça de suite

  12. #12
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    J'y comprend plus rien : cette fois les valeurs sont toujours tres bizarre mais coté serveur le getsockopt() renvoit 0 : voici les appels

    Coté serveur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    	int optval, optval1;
    	socklen_t optlen = sizeof(optval);
    	socklen_t optlen1 = sizeof(optval1);
    	cout << "Retour de getSockOpt() pour le sendbuffer: " << getsockopt(descBr, SOL_SOCKET, SO_SNDBUF,&optval, &optlen) << endl;
            cout << optval << endl;
    	cout << "Retour de getSockOpt() pour le receivebuffer: " << getsockopt(descBr, SOL_SOCKET, SO_RCVBUF,&optval1, &optlen1) << endl;
            cout <<optval1 << endl;
    Retour de getSockOpt() pour le sendbuffer: 0 50436
    Retour de getSockOpt() pour le receivebuffer: 0 87680


    Coté client maintenant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    	int optval, optval1;
    	socklen_t optlen = sizeof(optval);
    	socklen_t optlen1 = sizeof(optval1);
    	cout << "Retour de getSockOpt() pour le sendbuffer: " << getsockopt(descLocale, SOL_SOCKET, SO_SNDBUF,&optval, &optlen) << endl;
            cout  << optval << endl;
    	cout << "Retour de getSockOpt() pour le receivebuffer: " << getsockopt(descLocale, SOL_SOCKET, SO_RCVBUF,&optval1, &optlen1) << endl;
             cout <<optval1 << endl;
    Retour de getSockOpt() pour le sendbuffer: 0 50436
    Retour de getSockOpt() pour le receivebuffer: 0 87680

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ben... je peux pas trop te dire...
    Moi, je faisais ça sous Windows, et j'avais droit à des buffers de 8ko... Donc 50 et 80 ko, ça me parait un peu grand, mais c'est peut-être comme ça sous nux...

    Ben je peux pas vraiment t'aider, là... désolé...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  14. #14
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    Est-il necessaire que les buffers de snd et recv soient identiques ? je vais essayer de fixer de part et d'autre a 8092 on va bien voir

  15. #15
    Membre confirmé
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 394
    Points : 473
    Points
    473
    Par défaut
    Je n'ai pas parcouru le thread en détail, dsl, mais il y a quelque chose qui me semble louche dans le code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    while(octetsEnvoyes != tailleFichier)
    {
      octetsLus=fread(buffer, 1, 256, fichier);
       snd = send(descBr, buffer, octetsLus, 0);
       octetsEnvoyes = octetsEnvoyes + snd;
    }
    Que se passe-t-il si l'ensemble du buffer buffer n'est pas envoyé ?
    Dans mon souvenir, send retourne le nombre d'octets envoyé dans la transmission, mais il n'y a pas de garantie que tout ce que l'on souhaite envoyer (octetsLus ici) soit envoyé.
    Un mauvais envoi pourrais complétement desynchroniser la lecture du fichier et son envoi.

  16. #16
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    Tres interessant ca que tu me dis là, je vais me pencher sur le sujet et comparer snd avec la taille de buffer et eventuellement ne pas continuer tant que buffer en entier n'a pas été envoyé.

  17. #17
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    321
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 321
    Points : 360
    Points
    360
    Par défaut
    Bon je viens de faire un test et le probleme que tu me propose n'apparait pas (j'ai fait des affichages de valeur de snd et de la taille du buffer) mais j'ai tout de meme fait une verif au cas où. mais par contre cela continu a planter. La seule solution est de mettre le SO_SNDBUF du serveur à 2048 (a partir de 2500 ça plante en tout cas) et de laisser le SO_RCVBUF du client a la valeur d'origine soit 80000 et des poussieres. Et la ça marche .
    Ce probleme n'intervient que lorsque le client et le serveur sont sur la meme machine sinon aucune modif n'est necessaire c'est ça que je trouve bizarre

Discussions similaires

  1. Problème de Transfert de fichiers en TCP
    Par BibiDev11 dans le forum Entrée/Sortie
    Réponses: 1
    Dernier message: 22/11/2013, 11h44
  2. Fichier csv: Perte des 0 non significatifs lors d'un transfert unix vers windows
    Par moctarim dans le forum Shell et commandes POSIX
    Réponses: 2
    Dernier message: 03/01/2013, 13h28
  3. [AC-2007] Comment augementer timeout lors d'un transfert de fichier sur ftp
    Par pasnaz dans le forum VBA Access
    Réponses: 3
    Dernier message: 15/10/2009, 22h14
  4. transfert de fichier via TCP
    Par marion5515 dans le forum Entrée/Sortie
    Réponses: 6
    Dernier message: 29/02/2008, 11h06
  5. Ping sous protocole TCP (et non UDP)
    Par ovdz dans le forum Développement
    Réponses: 2
    Dernier message: 19/06/2003, 14h10

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