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

Windows Discussion :

[PC] Sockets avec API win32, bug incompréhensible


Sujet :

Windows

  1. #1
    Membre du Club
    Inscrit en
    Mai 2006
    Messages
    126
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 126
    Points : 54
    Points
    54
    Par défaut [PC] Sockets avec API win32, bug incompréhensible
    Bonjour,

    J'ai programmé un serveur multi-thread en c++, et l'une des tâche consiste à envoyer un fichier aux clients qui en font la demande. Ca marche correctement avec des fichiers TXT ou PDF. Par rencontre je rencontre deux problèmes lorsque j'essaie d'envoyer des fichiers EXE:

    1) La taille du fichier reçu est correcte, mais il est corrompu.
    2) Une fois le transfert terminé, il m'est impossible de supprimer du disque le fichier EXE (la source). J'ai essayer en redémarrant Windows, rien à faire. Windows dit que le fichier est utilisé par un processus. La seule façon que j'ai trouvée pour le supprimer est de démarrer en mode sans échec. Le problème apparaît pour tous les fichiers EXE que j'essaye d'envoyer.

    Notez que je fractionne le fichier en blocs de 4096 octets afin d'incrémenter une progress bar entre chaque bloc reçu.

    Voici le code source pour le 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
    fstream File;
    File.open("Source.exe",ios::in|ios::binary);
    File.seekg(0,ios::end);
    int FileSize=File.tellg();
    File.seekg(0,ios::beg);
    send(Socket,(char *) &FileSize,4,0); // J'informe le client de la taille du fichier qu'il va recevoir
    char *FileBuffer=new char[FileSize];
    File.read(FileBuffer,FileSize);
    File.close();
    int Remaining=FileSize;
    char *BufPtr=FileBuffer;
                    
    while (Remaining)
       if (Remaining>4096)
         {
           send(Socket,BufPtr,4096,0);
           BufPtr+=4096;
           Remaining-=4096;
         }
                        
       else
         {
           send(Socket,BufPtr,Remaining,0);
           Remaining=0;
         }
                      
    delete FileBuffer;
    Voici le code source pour le 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
    int FileSize;
    recv(Client,(char *) &FileSize,4,0);
    char *FileBuffer=new char[FileSize];
    int Remaining=FileSize;
    char *BufPtr=FileBuffer;
                    
    while (Remaining)
      if (Remaining>4096)
        {
          recv(Client,BufPtr,4096,0);
          BufPtr+=4096;
          Remaining-=4096;
        }
                        
      else
        {
          recv(Client,BufPtr,Remaining,0);
          Remaining=0;
        }
                  
    fstream File;
    File.open("Cible.exe",ios::out|ios::binary);
    File.write(FileBuffer,FileSize);
    File.close();
    delete FileBuffer;
    Merci d'avance pour votre aide!

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    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 381
    Points : 41 582
    Points
    41 582
    Par défaut
    send() et recv() n'envoient pas forcément (troisième paramètre) octets du premier coup. Tu dois utiliser la valeur retournée par send() et recv() pour savoir combien d'octets ont effectivement été envoyés ou reçus.

  3. #3
    Membre du Club
    Inscrit en
    Mai 2006
    Messages
    126
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 126
    Points : 54
    Points
    54
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    send() et recv() n'envoient pas forcément (troisième paramètre) octets du premier coup.
    D'accord, je vais vérifier cela. Mais si c'est effectivement le cas, est-ce qu'il faut redemander le transfert de tout le bloc, ou bien est-ce qu'il y a une commande pour demander l'envoie de la suite?

    Alors j'imagine qu'il faut d'abord que le client demande au serveur quelle est la taille du bloc que le serveur a l'intention d'envoyer (car la taille du dernier bloc est en général inférieur à 4096 bytes). N'est-ce pas?

  4. #4
    Membre du Club
    Inscrit en
    Mai 2006
    Messages
    126
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 126
    Points : 54
    Points
    54
    Par défaut
    Bon... Je me rends compte que mon problème ne se produit pas seulement lorsque je fragmente mon fichier, et qu'il se produit en fait avec tous types de fichiers.

    Alors pour récapituler et simplifier, je veux que mon serveur envoie un fichier quelconque à un client qui en fait la demande. Mon problème est que le fichier reçu est souvent corrompu. Suite à la réponse de Médinoc, j'ai remplacé les simples appels aux fonctions 'send' et 'recv' par:

    Coté 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
    fstream File;
    File.open("FichierSource.exe",ios::in|ios::binary);
    File.seekg(0,ios::end);
    int Size=File.tellg();
    File.seekg(0,ios::beg);
    char *Buffer=new char[Size];
    File.read(Buffer,Size);
    File.close();
    bool Test;
    int Sent;
    char Answer[3];
                        
    do
      {
        Sent=send(Socket,Buffer,Size,0);
        recv(Socket,Answer,3,0);
                         
        if (StringCompare(Answer,"Bad",3)==0)
          Test=true;
        else
          Test=false;
    
      } while (Test);
    
    delete Buffer;
    Coté client (il connaît la taille 'Size' du fichier à recevoir):
    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
    char *Buffer=new char[Size];
    bool Test;
    int Received;
                        
    do
      {
        Received=recv(Socket,Buffer,Size,0);
                           
        if (Received!=Size)
          {
            send(Socket,"Bad",3,0);
            Test=true;
          }
                           
        else
          {
            send(Socket,"Ok!",3,0);
            Test=false;
          }
                             
      }  while (Test);
    
    fstream File;
    File.open("Copie.exe",ios::out|ios::binary);
    File.write(Buffer,Size);
    File.close();
    delete Buffer;
    Ainsi, selon moi, le serveur envoit les données et attend la réponse du client. Si le client répond "Ok!" tout va bien, si le client répond "Bad" le serveur renvoit à nouveau les données. Le client quant à lui attend la réception de données. Si il reçoit le nombre d'octets attendus il envoit au serveur "Ok!", sinon il envoit "Bad" et attend à nouveau les données.

    RESULTAT: Ca marche mieux dans le sens qu'il y a moins d'erreurs, mais il y en a toujours. Je ne comprends pas, le bloc de donnée est transmis plusieurs fois jusqu'à ce que le client confirme au serveur qu'il l'a bien reçu. Je ne vois pas où est le problème? Y a-t-il un moyen plus sûr pour s'assurer que des données ont bien été envoyées et bien reçues?

  5. #5
    Membre du Club
    Inscrit en
    Mai 2006
    Messages
    126
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 126
    Points : 54
    Points
    54
    Par défaut
    Personne ne voit où est mon erreur?

Discussions similaires

  1. Application en C avec API win32
    Par bmchris dans le forum Bibliothèque standard
    Réponses: 2
    Dernier message: 27/06/2013, 10h38
  2. Réponses: 2
    Dernier message: 16/01/2009, 16h19
  3. plugin 4d avec api win32 gdi
    Par freehair dans le forum 4D
    Réponses: 2
    Dernier message: 31/03/2008, 09h46
  4. Affichage d'image avec API Win32
    Par Chess0 dans le forum Windows
    Réponses: 12
    Dernier message: 14/12/2005, 07h14
  5. [API WIN32] Pb avec SHGetSpecialFolderLocation
    Par Invité dans le forum MFC
    Réponses: 3
    Dernier message: 27/01/2004, 21h19

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