Bonjour à tous.
J’aimerais parler un peu socket encore un fois.
D’abord, je vous explique un peu la situation. Je réalise, pour être bref, une petite application capable d’envoyer des fichiers via un socket. Dans l’esprit, le serveur est celui qui permet d’envoyer les fichiers et le client permet de les recevoir. On ne parlera donc pas ici de « passive mode ».
Le traitement des informations se fait donc exclusivement via des buffer envoyés entre les clients et les serveurs.
Les structures de mon code sont en gros :
La taille du bloc (assez énorme il est vrai) donnera la taille des données lues dans le fichier que l’on appellera « bloc ».
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 const taille_bloc =4000; taille_direction_fichier =255; type T_Trame_client =Packed record fichier_req : string[taille_direction_fichier]; bloc, nbr_trame : integer; //4 bytes end; //Soit un total de 255+4*2 = 263 bytes type T_Trame_serveur =Packed record bloc, taille_envoye,nbr_bloc : integer; //4 bytes nbr_trame_restant : integer; //4 le_bloc : array[0..taille_bloc-1] of Byte; end; //Soit un total de 4000+4*4 = 4016 bytes
La trame est donc l’ensemble des données envoyées protocole compris. Ici le protocole est donc pour le client :
- -le fichier désiré (fichier_req)
-le numéro du bloc désiré (bloc).
-La variable nbr_trame permettra de demander au serveur plusieurs trames à la suite sans avoir à les équités à chaque arrivés.
Du coté serveur, protocole est le suivant :
- -Bloc est numéro du bloc du fichier envoyé,
-Taille_envoye est la taille du bloc lu dans le fichier
-Nbr_bloc est le nombre de bloc que contient le fichier
-nbr_trame_restant est le nombre de trame que le serveur va envoyer sans attendre d’acquittement de la part du client. Ce nombre se décrémente jusqu’à 0 et à ce moment, le paquet composé de Trame_client.nbr_trame est terminé.
Cette structure me permet donc de me connecter à un serveur quelconque et du lui demander un bout quelconque d’un fichier quelconque. On approche donc du principe du P2P. De plus, le client va être capable de gérer de lui même le nombre trames qui composeront le paquet serveur.
Bon, maintenant je développe la partie OnServerRead et OnClientRead. Le coté server reçoit à chaque fois des petites trames et les traite facilement. Le coté client est déjà plus interressant puisque il contient à la fois un protocole à traiter mais aussi des données brutes à gérer (le_bloc). Il est donc important de vérifier la taille de la trame du serveur pour qu’elle puisse être intégrée à une variable de type T_Trame_Serveur. On en vient donc aux suprises…
D’abord, je constate que le buffer reçu du coté client est parfois bien plus gros que 4016 mais surtout, qu’il est parfois trop petit pour être contenu dans ma variable. En effet en envoyant plusieurs trames à la suite, il arrive que celles-ci s’accumulent dans le buffer et du coup, sa taille s’en trouve souvent multipliée par 2.
La solution est donc de forcer la lecture du buffer avec la taille adéquate à ma variable de type T_Trame_server.
Mais la, ho surprise, le socket me régénère automatiquement un OnRead pour me signaler qu’il reste des données dans le buffer.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 Socket.ReceiveBuf(ma_trame_serveur,taille_bloc+16);
Ca m’a bien arrangé car j’ai pu lire bout par bout le buffer. Mais par la suite, lorsque je reçois des données trop petites, ne sachant ou les mettre temporairement, il ne me suffit finalement que de simuler une lecteur du buffer
Ce qui à pour effet de laisser les données dans le buffer et de me régénérer un OnRead. Je boucle donc de cette façon jusqu’à ce que le buffer soit d’une taille adéquate pour enfin enclencher la vraie lecture du buffer et les traitements.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 Socket.ReceiveBuf(ma_trame_serveur,0);
Mais le problème est que la boucle sur l’événement OnRead est très rapide et utilise beaucoup de ressources. J’aimerais pouvoir dire au socket de me générer le prochain OnRead lorsque d’autres données arriveront et non pas tout de suite.
Bon au finale super ça marche, mais les testes vont me réserver encore des surprises. D’abord, je suis capable de pousser la taille de mon buffer à 8192 octets en local, mais aussi sur internet alors que la taille de la trame Ethernet ne devrait pas dépasser 1500 octets je croyais ! Je pense que TCP fait lui même le travaille de composition et décomposition de paquet mais je ne comprends pas pourquoi il la fait autant varier au début et la rend stable par la suite. En effet lorsque je teste l’application sur le net, les trames sont d’abord toutes différentes, trop petites, trop grandes, pour finalement tendre vers une taille fixe correspondant (miraculeusement) à la taille prévue dans ma variable.
L’autre surprise que j’ai eue est que lorsque j’envoie plusieurs trames à la suite, au bout d’un certain temps, la réception se bloque. En gros, mes paquets ne peuvent pas se composer de plus de 5 trames sans quoi la 6° n’est jamais reçue. En local, je peux aller jusqu’à 18 trames par paquets mais pas plus. Si je n’acquitte pas au bout de ce nombre de trame, la réception se bloque. Je me demandais si ça n’était pas aussi TCP qui me provoquait ce blocage en réception et si on ne pourrait pas savoir cette limite à l’avance.
Enfin, l’ordre des trames reste le même alors que je présume, toutes mes trames ne suivent pas le même chemin. Pourtant même si j’envoie 4 trames à la suite, l’ordre sera toujours le bon à l’arrivée alors que ces trames sont indépendantes ! Encore TCP IP ?
Résumé :
- [Résolu] 1 – Est-ce bien TCP qui choisit la taille de mes trames envoyées sur internet ?
[Résolu] 2 – Si oui, comment savoir à l’avance (si c’est possible) le résultat de la négociation avec TCP et la machine ?
[Résolu]3 – Comment dire au socket de ne pas me générer de OnRead avant la prochaine réception de données tout en gardant le buffer actuel. Ma solution (simuler une lecture) ne me semble pas très propre.Envoyé par cpdump
[Résolu] 4 – Pourquoi au bout d’un certain nombre de trames sans acquittement, la réception se bloque alors que le serveur semble bien avoir émis le paquet. Donc en gros, si je lis, du coté client, plus de 18 Onread ou sur le net, plus de 5 Onread, sans envoyer une donnée quelconque (acquitement ou n'importe quoi) la récéption se bloque. On dirait qu'il faut absolument que j'envoie des données dans mon socket client tous les x secondes ou tous les x paquets, sans quoi, la récéption se bloque. Et je ne comprend pas comment éstimer cette limite (x).Envoyé par gord's
[Résolu] 5 – Si c’est bien normal, comment savoir la limite de taille des paquets.
[Résolu] 6 – Comment se fait-il que mes trames, envoyées indépendamment les unes des autres arrivent finalement toujours dans le même ordre qu’à l’émission (TCP ? ) ?Envoyé par cpdump
[Surement mais ça va mieux]7 - Y a-t-il quelque chose qui je semble ne pas avoir saisi sur les transfères de fichier ou le principe du TCP/IP ?Envoyé par cpdump
Voilà, désolé pour la longueur du post mais ça méritait une légère mise en contexte.[fautes corrigées]
Partager