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 :

Explications concernant la réception de données


Sujet :

Réseau C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 23
    Par défaut Explications concernant la réception de données
    Bonjour à tous,

    Il y a quelque chose qui m'est encore très mystérieux en rapport avec la réception de données et je suis d'ailleurs confronté à un problème à ce niveau, alors j'apprécierais avoir quelques explications.

    Je travaille sur la réception de fichiers et je dispose d'une structure d'entête pour connaître la taille des données à recevoir. En ce moment, je planche sur un problème d'erreur socket (code 10055) et donc je ne comprends pas vraiment comment tout est géré niveau système en fait.
    Le serveur envoie un nombre n de fichiers (j'ai défini un protocole d'envoi) et tout semble aller de ce côté. Le processus client pour la réception suit le même protocole (petite précision : j'utilise le protocole TCP-IP donc tout est ordonné).
    J'imagine que le serveur se fiche de savoir comment est gérée la réception et qu'il se contente d'envoyer les paquets, mais voilà, là, ça plante ! Le client qui reçoit les données crash au bout d'un certain nombre d'appels à recv() et l'erreur socket rencontrée me laisse penser que le buffer système est engorgé par les paquets, mais est-ce vraiment le fond du problème ?

    Ca plante plus particulièrement lorsque je reçois les blocs de données qui constituent les fichiers du serveur. Pourtant, jusqu'au moment auquel survient l'erreur, tout ce qui est récupéré est testé est écrit, alors j'aimerais savoir à quel moment le buffer système libère des ressources ? N'est-il pas censé être vidé au fur et à mesure que je récupère les données dans mon buffer logiciel ?

    Je pense que le problème peut provenir du fait que j'examine mal les points-clés du code. En effet, j'utilise des MessageBox() pour contrôler la réception de chacun des fichiers et donc ça peut bloquer la réception du fichier n+1, pendant que le serveur continue à envoyer des données. Du coup je peux comprendre cet engorgement.

    Mon soucis majeur est que, si je ne mets plus aucun contrôle (suppression des MessageBox()) pas grand chose ne va : certains fichiers sont bien transferés et d'autres non, parfois ça crache avant la fin du processus de réception, tout est fonction du nombre de fichiers à recevoir en fait.
    Il n'y aurait pas un moyen de pouvoir rendre tout ça plus propre, plus fiable ?
    J'ai pensé à envoyer un message depuis le client vers le serveur pour lui indiquer que j'ai bien reçu un bloc après chaque réception mais ça me semble assez paradoxal puisqu'à mon avis un problème de "transfert" ne se résout pas avec d'autres transferts...

    Y a t-il un moyen de connaître la taille des ressources occupées dans le buffer système de ma socket de réception ?

    J'ai tenté d'utiliser setsockopt() pour modifier en l'augmentant la taille maximale du buffer système mais ceci reste approximatif et pas forcément une solution de choc, non ?

    Pour que vous y voyez un peu plus clair, je procède comme ceci :

    Côté serveur :
    (en pseudo-code)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    // Il y a n fichiers à envoyer :
     
    TQ nombre de fichiers envoyés < nombre de fichiers à envoyer
     
              Envoyer tailleFichier
              Envoyer nomFichier
              TQ nombreOctetsEnvoyes < nombreOctetsAEnvoyer // boucle d'envoi des blocs de données)
                     Envoyer bloc de données
                     nombreOctetsEnvoyes = taille du bloc
              FTQ
    FTQ
    Je précise qu'avant chaque envoi, j'envoie l'entête et du coup, le nombre de recv côté client est égal au nombre de send côté serveur. Je tiens à préciser que je teste toujours la valeur de retour des fonctions sockets.

    Comment s'y prendre pour que tout soit fiable, peu importe le nombre de fichiers à transférer, leurs tailles respectives, etc. ?

    Merci par avance !

  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 : 62
    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
    Par défaut
    Ton problème ressemble à une perte de synchronisation entre l'émetteur et le récepteur.

    J'ai l'impression qu'il manque la longueur du nom du fichier ce qui fait que cela peut parfois désynchroniser.

    Autre point, tes fichiers ont bien ouverts en mode binaire ?
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 23
    Par défaut
    La longueur du nom du fichier est bien envoyée dans l'entête, juste avant la réception du nom lui-même.
    J'ai testé tout un tas de choses aujourd'hui et j'en suis arrivé à la conclusion qu'il y a effectivement un problème de synchronisation. Le buffer système est engorgé et le timeout pour le vider n'est pas assez rapide. Je pense que je vais tester une solution à laquelle j'avais penser plus tôt : assurer au serveur qu'il peut envoyer un bloc qu'à partir du moment ou le client a traité le bloc précédent.

    J'ouvre bien tous mes fichiers en mode binaire, oui.

    Je vous tiens au jus !

  4. #4
    Membre émérite Avatar de orfix
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 707
    Par défaut
    Citation Envoyé par whoeao
    ...le nombre de recv côté client est égal au nombre de send côté serveur...
    Attention, pour un send() il faut parfois (souvent même) plusieurs recv(). Souviens-toi que recv() retourne le nombre de bytes reçus.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 23
    Par défaut
    Citation Envoyé par ssmario2 Voir le message
    Attention, pour un send() il faut parfois (souvent même) plusieurs recv().
    Même dans le cas où les sockets sont bloquantes et que pour chaque appel à recv() je sais exactement combien d'octets je dois recevoir ?

  6. #6
    Membre émérite Avatar de orfix
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 707
    Par défaut
    Citation Envoyé par whoeao Voir le message
    Même dans le cas où les sockets sont bloquantes et que pour chaque appel à recv() je sais exactement combien d'octets je dois recevoir ?
    Citation Envoyé par man recv
    If no messages are available at the socket, the receive calls wait for a message to arrive, unless the socket is non-blocking (see fcntl(2)), in which case the value -1 is returned and the external variable errno set to EAGAIN. The receive calls normally return any data available, up to the requested amount, rather than waiting for receipt of the full amount requested.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 23
    Par défaut
    Merci !

    J'ai implémenté la démarche de demande(s) de bloc(s) et leur envoi depuis le serveur qu'après réception d'une demande du client, mais là, un problème est apparu. Si j'ai n fichiers à envoyer du serveur vers le client, je lance mon processus d'envoi des fichiers (en suivant mon protocole d'envoi) : le premier fichier est toujours bien envoyé et bien reçu, bien reconstitué, peu importe sa taille. Après ce premier transfert, le serveur crash. Dans ma boucle de réception des fichiers côté client, l'appel à recv() renvoie l'erreur socket 10054 (la socket serveur semble mourir, non ?) quand je souhaite obtenir l'entête pour la taille du prochain fichier à recevoir.
    Le problème survient même quand n = 1 et toujours exactement au même moment pendant l'exécution du code :

    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
    50
    51
    52
    // (Je synthétise le code côté serveur)
    /* J'ai un vector qui contient des CString qui ont pour valeur un nom de fichier */
    int nombreFichiersAEnvoyer = monVecteur.size();
    for(int i = 0; i < nombreFichierAEnvoyer; i+=1)
    {
         // Envoi de l'entête pour la taille du fichier
         // Envoi de la taille du fichier
    
         // Envoi de l'entête pour le nom du fichier
         // Envoi du nom du fichier
    
         if(tailleFichier > 0)
         {
              int octetsEnvoyes = 0;
              bool demande = true;
              
              // Ouverture du fichier en lecture
              while(octetsEnvoyes < tailleFichier)
              {
                    if(demande)
                    {
                         if(size - octetsEnvoyes >= 4096)
                         {
                              // Envoi de l'entête du bloc de données, taille bloc = 4096
                              // Envoi du bloc de données
                              octetsEnvoyes += resultatRecvDonnees
                              demande = false;
                              
                              if(octetsEnvoyes < tailleFichier)
                              {
                                    // Reception demande
                                    // Verification de la valeur de la données reçue
                                    if(donneeRecue == 1)
                                          demande = true;
                              }
                              
                         }
                         else
                         {
                              // Envoi entête bloc de données, taille bloc = tailleFichier - octetsEnvoyes
                              // Envoi du bloc de données
                              octetsEnvoyes += resultatRecvDonnees
                              demande = false;
                         }
                    }
              }
              // Fermeture du fichier
              
         }
         CRASH ICI, NE RETOURNE PAS EN DEBUT DE BOUCLE : ENTRE CES DEUX ACCOLADES, AUCUNE INSTRUCTION N'EST FAITE
    }
    Sur le net j'ai vu ce topic : Unknown socket crash (10054) - C code

    J'ai bien évidemment essayé mais ça n'a pas changé le problème. Peut-être ai-je mal implémenté la solution ?

    J'utilise setsockopt() aussi bien du côté serveur que du côté client. Côté client, je le fais juste après le retour de connexion et côté serveur, je le fais juste après acceptation d'une demande de connexion, sur la socket d'écoute.

    Je ne vois vraiment pas ce qui se passe... je n'ai aucun moyen de tracer l'erreur. Vous voyez peut-être quelque chose ?

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 23
    Par défaut
    Je résume un peu la situation :

    - Le crash se produit à la fin de l'envoi du premier fichier. A ce moment là, il n'y a plus d'appel de fonctions socket, le dernier paquet contenant le reste des données du fichier a été envoyé et reçu par le client. J'ai testé des dizaines de fois le processus, pour des fichiers de taille différente (entre 10ko et 1mo).
    - Pour parler un peu de mon serveur : j'effectue deux appels à CreateThread(); 1 pour le mettre en écoute et 1 autre pour qu'il s'occupe d'une connexion. C'est dans ce dernier thread que les fichiers sont envoyés.

    L'application entière crash, mais est-ce que cela pourrait être dû au crash d'un thread qu'il appelle ?

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    23
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 23
    Par défaut
    Bonjour ,

    Je suis tombé sur ce sujet à l'instant :

    socket-buffer-tcp

    Et je dois avouer que j'y vois beaucoup plus clair ! Maintenant il y a quelques informations manquantes pour mon cas. J'ai implémenté la méthode d'acquittement, donc c'est plus sécurisé. Par ailleurs, j'ai légèrement modifié mon code en réception et je ne travaille plus sur la base d'une égalité entre nombre d'appels à send() et recv(). Je trouve que ce genre d'informations manquent dans les différents tutoriels du site, mais j'imagine qu'en dire plus obligerait à sortir du contexte quelque part.
    J'ai testé différentes choses... au départ, je pensais qu'en mettant en place la demande d'acquittement, il fallait augmenter la taille des buffers en émission et/ou réception, pour éviter un trop grand nombre de transferts de paquets. Je travaillais sur des buffers char de 2048 octets à la base et j'ai donc doublé leur taille. Dans mes précédents messages, je parle d'un crash serveur... je n'ai toujours pas bien compris ce dernier, mais en ré-utilisant la taille de base pour mes buffers, je n'ai plus ce problème là.

    Voilà où j'en suis :

    J'arrive à transférer des fichiers de + ou - 20MO, mais la reconstruction des fichiers n'est pas parfaite : les fichiers reconstruits ont toujours une taille supérieure (Je précise pourtant bien fstreams que le mode binaire doit être utilisé) et plus je diminue la taille de mes buffers, plus la reconstruction semble se rapprocher de la perfection. Le soucis est que j'aimerais bien pouvoir conserver un buffer char[] de 1024 cases pour la réception, et un buffer char[] de 2048 cases pour l'envoi.

    J'ai eu l'occasion de jeter un oeil sur un autre sujet également. Il y est dit qu'il faudrait lire octet par octet, dois-je comprendre qu'il faut appeler recv() en passant une taille de 1 octet en paramètre ?

    Pourquoi y'a t-il une si grande différence entre ce qui est logiquement vérifié et facilement vérifiable dans le code (taille des données reçues, taille des données restantes, taille des données à écrire dans un fichier, etc.) et ce qui se passe réellement ?
    Par exemple, j'ai une boucle de réception pour un fichier qui prend fin lorsqu'une variable indiquant le nombre d'octets reçus est égale à la taille du fichier. Pourtant, à la fin, la taille de mon fichier est différente du nombre d'octets reçus, mais pourquoi ça ? (et ça varie en fonction de la taille des buffers).

Discussions similaires

  1. Réponses: 2
    Dernier message: 06/06/2006, 12h10
  2. Réponses: 7
    Dernier message: 22/05/2006, 14h44
  3. Réponses: 9
    Dernier message: 09/05/2006, 16h11
  4. [VB6]Réception de données sur port série
    Par lindecker dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 08/03/2006, 06h48
  5. Réponses: 5
    Dernier message: 11/03/2004, 15h34

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