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 :

TCP et transfert de fichiers : Perte de données ?


Sujet :

Réseau C

  1. #1
    Membre averti
    Inscrit en
    Octobre 2006
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 21
    Par défaut TCP et transfert de fichiers : Perte de données ?
    Bonjour,

    J'en appelle à votre expérience en matière de sockets, car je suis confronté à un problème dont j'ignore l'origine.


    Ce que je cherche à faire est assez rudimentaire : Transferer de gros fichiers ( plusieurs Mo ) à travers le réseau, en utilisant TCP.

    Je vais donner assez peu de code. En fait, j'aimerais cibler mon problème par élimination.

    Pour résumer le fonctionnement de mon programme : (et admettant ici que le client envoie et que le serveur recoit)
    a. Le Client lit le fichier pour détecter sa taille, et décide d'une méthode/plitique de découpage en "morceaux" (j'appelle les morceaux "chunk") d'environ 1 Mo.
    b. Une structure contenant la politique de découpage est envoyée au Serveur (qui sait alors comment recevoir les data)

    c. Ensuite, le client lit un morceau qui est découpé en fragments (de 1208 octets, mais cette taille, à terme, devra varier selon la MTU détectée) qui sont placés dans une structure toute simple (numero du fragment + taille du fragment + data du fragment)
    d. Le Client envoie ces fragments au Serveur, les uns après les autres. Le serveur est déjà prêt à les recevoir.
    e. Une fois que le Serveur a reçu suffisament de fragments pour assembler un chunk (morceau), il écrit ce morceau dans le disque dur.

    Les étapes c,d,e sont répétées jusqu'à ce que le fichier soit totalement envoyé/reçu.


    PROBLEME (enfin !) : Parfois, le Serveur ne reçoit pas tous les fragments envoyés par le Client (tout se passe bien côté Client), et tombe dans un boucle en recevant des data de 6 à 7 octets (au lieu de 1200). J'ai fait en sorte d'ignorer (mais d'afficher sur la console) ces data "parasites" reçues. A noter que le Serveur continue à recevoir ces data même quand le Client a cessé d'émettre.
    En fait, tout ce passe comme si le Serveur ne recevait pas tout ce que le Client envoie, ce qui fait qu'une fois le Client muet, le Serveur continue à attendre le "fragment 878 du chunk 31" (exemple) mais reçoit des données incorrectes. (6 à 7 octets)

    Ce qui m'étonne, c'est que le protocole TCP est un protocole sûr, (et c'est là que j'aimerais que vous m'arrêtiez si je me trompe), et il n'est donc pas nécessaire de coder manuellement un "acquittement" après chaque bloc reçu, puisque l'ID et trames (ordre) et le handshake TCP (bien reçu) sont censés gérer ça, à plus bas niveau.
    J'ai donc pensé que le Serveur "loupait" des trames envoyées par le Client (ça en présent tous les symptomes, car le Client semble aller plus vite), mais là aussi, il me semble que c'est le boulot de TCP. Y a t'il un délai à respecter entre les envois des différentes trames ? Y a t'il une limite au bout de laquelle le Serveur aurait reçu "trop de trames" et arrêterait sa lecture ? Je pense que non, mais comme je ne trouve pas la source du problème, j'ose espérer que quelquechose m'aie échappé sur la façon dont transitent les données.


    Je précise que ce problème survient tant sous Windows (winsock) que sous Linux.
    Je précise également que j'ai effectué les tests en localhost (si, au passage, quelqun sait comment observer les packets "locaux" avec Wireshark ...)


    Voilà, message un peu capilo-tracté. L'objectif est que quelqun trouve une connerie dans les affirmations que je fais là haut. (qui pourrait être la source de mon problème). Dans le cas contraire, de longues heures (encore) de fouinage m'attendent.


    Bouts de code (inutiles normalement, car c'est sur le principe interne des sockets que je m'interroge) :

    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
    	int i;
    	for ( i=0; i < fileConf->splitting_configuration.nb_chunks; i++ ) {
     
    		file_chunk fc;
     
    		fragment_chunk( i, fileConf, &fc );
     
    		int j;
    		for (j=0; j<fc.nb_fragments; j++) {
     
    			if ( ( dataCount = send(sock, &fc.fragment[j], sizeof(fc.fragment[j]) , 0)) < 0 )  {
     
    				return -2;
     
    			}
     
    			if ( dataCount != sizeof(fc.fragment[j]) ) {
     
    			}
     
    		}
     
     
    	}

    Serveur :

    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
    44
    45
    46
    47
    48
    49
     
                   totalReceivedSize = 0;
     
    		fc.fragment = (file_chunk*) calloc( 0, sizeof(chunk_fragment) );
     
    		while ( totalReceivedSize < chunk_size && status == 1) {
     
    			errorh = 0;
     
    			fc.fragment = (chunk_fragment*) realloc( fc.fragment, sizeof(chunk_fragment) * (j+1) );
     
    			int dataCount;
    			if ( ( dataCount = recv(sock, &fc.fragment[j], sizeof(fc.fragment[j]) , 0)) < 0 )  {
     
    				printf("Reception error : %d\n", dataCount);
    				print_time();
    				return -2;
     
    			}
    			else {
     
    				if ( dataCount == fc.fragment[j].frag_size + (sizeof(int) * 2) ) {
     
    					if ( fc.fragment[j].id == j ) {
     
    						totalReceivedSize += fc.fragment[j].frag_size;
     
    						prevSize = fc.fragment[j].frag_size;
    						prevId = fc.fragment[j].id;
     
    						j++;
     
    						if (totalReceivedSize >= chunk_size ) {
    							printf("%d -> last chunk ! (%d/%d)\n", j+1, totalReceivedSize ,chunk_size );
    						}
     
    					}
     
     
    				}
     
     
    			}
     
    		}
     
    		fc.nb_fragments =  j;
     
    		assemble_chunk( i, &fileConf, &fc );

  2. #2
    Membre averti
    Inscrit en
    Octobre 2006
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 21
    Par défaut
    EDITO :

    Toujours le même soucis. Mais je pense que j'ai davantage ciblé le problème :

    Dans la boucle du serveur (les appels à "recv"), si je mets des opérations "lourdes" à chaque tour de boucle (par exemple, un "printf()", ou des Sleep d'une milliseconde), tout se passe bien. Par contre, lorsque la boucle du serveur tourne plus vite (sans les "printf()"/"Sleep"), c'est là que ça plante (la taille reçue est la bonne, mais les données récupérées semblent corrompues).

    Je pense donc que la boucle de mon serveur va "trop vite", ce qui est bizarre, car les "recv" sont bloquants par défaut. (dans le doute, j'ai utilisé des "select" pour m'assurer que des données soient dispos avant envoi ou réception).

    Honnêtement, je suis complètement bloqué, et j'arrive pas à progresser à cause de ça ... je pensais que toutes les opérations étaient bloquantes et qu'aucun des deux partis ne pouvait "aller trop vite", mais j'ai dû louper quelquechose d'important ..

  3. #3
    Membre chevronné Avatar de Mandraxx
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Mai 2011
    Messages
    182
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Architecte de système d'information
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2011
    Messages : 182
    Par défaut
    Bonjour,

    Tous les prédicats énoncés me paraissent correct. Il m'est déjà arrivé de rencontrer ce genre de phénomène qui sont en général dus à une mauvaise gestion de la mémoire.

    En effet, on se focalise sur l'aspect réseau alors qu'en fait recv fonctionne très bien mais retourne une valeur négative quand il n'y a pas assez de place dans le buffer de stockage.

    Le printf qui corrige le tir est un symptôme assez fréquent : ses algorithmes nettoient la mémoire du processus et certaines anomalies qui devraient conduire à un SIGSEGV ne se produisent pas : perso, j'essaierais donc de dumper en hexa les paquets pour analyse et de suivre l'algo pour voir s'il n'y a pas un dépassement quelque part...

    @+

Discussions similaires

  1. Manipulation de fichiers : perte de données
    Par Vojenbon dans le forum Débuter
    Réponses: 24
    Dernier message: 05/03/2010, 16h44
  2. Réponses: 3
    Dernier message: 16/02/2006, 18h38
  3. Réponses: 16
    Dernier message: 28/11/2005, 19h09
  4. [TCP] Pb transfert de fichier
    Par leyee dans le forum Réseau
    Réponses: 5
    Dernier message: 27/11/2005, 11h28
  5. Réponses: 6
    Dernier message: 04/05/2005, 09h58

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