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 );
Partager