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

C++Builder Discussion :

Récupérer une image avec un socket?


Sujet :

C++Builder

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2011
    Messages : 19
    Points : 17
    Points
    17
    Par défaut Récupérer une image avec un socket?
    Bonjour,

    je suis sur un projet informatique et j'essaie de récupérer une image sur un serveur (en http). Je développe sur l'ide c++ builder 6..
    j'utilise un socket afin de récupérer l'image en mémoire dans un flux, mais j'ai un problème:
    Lorsque j'utilise la fonction ReceiveLenght je n'arrive pas à recevoir la bonne taille de trame. Le serveur m'envoie une trame PLUS longue que ce que me retourne ReceiveLength.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    void __fastcall TForm1::SocRead(TObject *Sender, TCustomWinSocket *Socket)
    {  
            int nReceived = Socket->ReceiveLength(); // nombre d'octets reçus
            char buffer[102000]; // buffer de récupération des paquets venant du serveur
     
            Socket->ReceiveBuf(buffer, nReceived);  // lis que les 200 premier caractères la plupart du temps
            pStream->Write(buffer, nReceived );       // transférer dans le stream
                                                  // pour traitement ultérieur
    }
    L'avantage c'est que je reçois bien des données, et j'ai vérifier avec le débogueur je reçois les bonnes données [trame réponse + données (image)].
    Néanmoins, je ne reçois quasiment jamais la trame complète à cause de ce problème. Est-ce que vous savez comment résoudre ce problème? avez vous une autre méthode de réception d'une image à me proposer?

    Je suis preneur sur toutes les solutions que vous pourriez me proposer.
    J'attends avec impatience vos réponses, merci !

  2. #2
    Membre confirmé Avatar de themadmax
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    446
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 446
    Points : 496
    Points
    496
    Par défaut
    Je ne maitrise pas C++ buider, mais pour la programmation réseaux j'utilise courrament les outils comme wireshark et le plugin firefox LiveHTTPheaders. Wireshark (anciennement ethereal) te permet de sniffer toutes les trames de ton ordi, ce qui permet de comprendre debugger finement les échanges réseaux. L'outil telnet peut aussi te permettre d'envoyer des requettes à un serveur HTTP, et d'afficher le retour.
    ________________________________________________
    http://bliquid.fr : Blog sur Android et l'Acer Liquid

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 460
    Points : 24 877
    Points
    24 877
    Par défaut
    Pourquoi un socket pour un server HTTP ?
    Tu ne pouvais pas faire un GET\POST via un THTTPRio ou un TIdHTTP ?

    Sinon, c'est tout à fait normal, j'ai fait l'équivalent en Delphi, mon code est simpliste mais lorsque tu as une connexion client qui récupère une trame depuis un Serveur, ça passe si il y a une pause entre deux images

    En général, tu vas recevoir, avec les composant TClientSocket, des paquets de 8Ko, cela correspond en général au tampon de la carte Ethernet (et à l'implémentation du TCP\IP de l'OS), une fois plein, c'est l'OS qui récupère le paquet et signal au socket de lire les données, pendant ce temps, la carte continue a recevoir de données, le tampon se remplit, l'OS le récupère, je ne sais pas si il y a une limite évidemment dans l'OS de paquets stockés, si le client ne lit pas la socket assez régulièrement de dépasser le tampon de windows, je ne sais pas ce qui se passe à ce moment, je ne l'ai jamais tenté !

    Par conséquent, tu dois manuellement accumulé les suite de paquet de 8Ko jusqu'à ce qu'il n'y ait plus de données !
    En général, tu sais qu'un stream se termine par un pacquet d'une taille inférieure à 8Ko, puis un paquet de taille zéro indiquant la fin d'un stream, puis le stream suivant reprend un cycle de paquet de 8Ko...

    Il arrive que deux stream arrivent de façon très rapproché, et là cela peut poser problème car tu ne sais pas où se termine le premier message et où commence le second message

    Voici deux sujets (attention, il y a de nombreux liens vers d'autres sujets, la lecture de l'ensemble pourrait t'aider à mieux comprendre le protocol TCP\IP)
    Envoi donnes par socket
    Socket et envoi d'image
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  4. #4
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2011
    Messages : 19
    Points : 17
    Points
    17
    Par défaut
    Tout d'abord merci grandement pour votre attention face à mon soucis

    J'ai réussi à palier mon problème de base: il suffisait juste de récupérer la valeur de retour de la fonction ReceiveBuf et non ReceiveLength !

    Effectivement ReceiveLength est assez mal foutu elle retourne pas les bonnes valeurs tout le temps. j'ai tout simplement fait cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void __fastcall TForm1::SocRead(TObject *Sender, TCustomWinSocket *Socket)
    {
            char buffer[102000]; // buffer de recuperation des paquets venant du serveur
     
            int nbLu = Socket->ReceiveBuf(buffer, 102000 );  // lire les paquets
            pStream->Write(buffer, nbLu);       // transferer dans le stream
                                                  // pour traitement ulterieur
    }
    J'avais mal étudié la doc de borland .
    Par contre maintenant j'essaie de décoder cette trame et c'est pas gagner.
    J'isole le contenu de l'image et j'essaie de l'afficher sur mon IHM mais ça me met une erreur de jpeg: 'JPEG error #41'. -> Je me suis pourtant assurer d'isoler la partie de la réponse [de FFD8(début jpg) à FFD9(fin jpg)]...

    ShaiLeTroll, j'utilise un socket parce que je ne sais pas faire autrement. J'ai utilisé un TNMHTTP mais je n'arrivais pas à traiter l'image en mémoire (j'étais obligé de l'enregistrer sur mon disuqe dur).

    SI tu as une méthode plus simple avec les composants que tu as cités je suis preneur. Un exemple d'utilisation par exemple?

    Merci encore pour tout !

  5. #5
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2011
    Messages : 19
    Points : 17
    Points
    17
    Par défaut
    Voici les instructions que j'utilise:

    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
     
    i = 0, j = 0;
        int comp;
        unsigned char var[4], var2[4]="ÿØÿþ", tab;      // ÿØÿþ=FFD8.... 
     
        pStream->Position = 2;  
        while(pStream->Read(var,4)){
            i+=4;
            comp = strncmp(var,var2,4);
            if(comp == 0) break;
        }
        i-=2;
        pStream->Position = i;
        pStream->Read(var,4);
        pStream->Position = 0;
        while(pStream->Read(&tab,2)){
            j+=2;
            if(!strncmp(&tab,"ÿ",2)){
              pStream->Read(&tab,2);
              j+=2;
              if(!strncmp(&tab,"Ù",2)){
                break;                  //si on a FFD9 on quitte 
              }
            }
        }
        tailleImage = j - i;    //déclaré dans le .h
     
        DisplayImage();   //traite et affiche l'image
    Et voici le contenu de la fonction DisplayImage :

    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
     
      TJPEGImage* jp = new TJPEGImage;      // necessite //"jpeg.hpp"
      unsigned char buf[100000];
     
     
      try
      {
        pFluxImage->Position = 0;
        pStream->Position = i;// debut code jpeg après le Header dans le stream
        pStream->Read(buf, tailleImage);
        pFluxImage->Write(buf, tailleImage);
        jp->LoadFromStream(pFluxImage);     // charger le jpeg converti en bitmap
        Image1->Picture->Assign(jp); // afficher l'image
        Application->ProcessMessages();  //à partir de ce moment: message d'erreur...
      }
      catch (...)
      {
        MessageBeep(0);
      }
      delete jp;            // liberer la memoire

  6. #6
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2011
    Messages : 19
    Points : 17
    Points
    17
    Par défaut
    petit up please

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 460
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 460
    Points : 24 877
    Points
    24 877
    Par défaut
    Tout les JPEG ne commencent pas par "ÿØÿþ" FF D8 FF FE
    Certe FF D8, je te l'accorde mais pas FF FE

    Cherche des char, alors que l'on manipule du binaire, je ne suis pas un fan !
    je ne maîtrise pas bien les types C++, j'ai cru comprendre que unsigned char était l'équivalent du Byte en Delphi ?

    ensuite, pourquoi 2 dans tab c'est un char, 1 octet, tu veux en écrire deux ?
    ça va écrire ou dans la mémoire ?
    pourquoi 2 dans Tu ne compare qu'un caractère donc 1 pas 2 !

    j'ajouterais un seek après le Write qui a changé la position dans le stream, et donc j'ai un doute LoadFromStream charge depuis la position en cours !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    pFluxImage->Write(buf, tailleImage);
    pFluxImage->Position = 0;
    jp->LoadFromStream(pFluxImage);     // charger le jpeg converti en bitmap

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Application->ProcessMessages
    A quoi ça te sert ?
    fait un Image1->Refresh si tu veux forcer l'affichage !
    ProcessMessages, c'est utile pour gérer les messages windows (comme WM_PAINT, WM_MOUSE...) dans une boucle, si tu veux que l'application ne soit pas bloqué !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vaucluse (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2011
    Messages : 19
    Points : 17
    Points
    17
    Par défaut
    Quasiment tous les jpeg commencent par "ÿØÿþ" ou "ÿØÿÀ", je pense qu'il y a plusieurs types de jpeg(.jpeg, .jpg)? En tout cas ce que j'essayais de récupérer ça commençais toujours par FF D8 FF FE.

    Ceci étant un énorme merci à toi tu as su m'éclairer:
    pFluxImage->Write(buf, tailleImage);
    pFluxImage->Position = 0;
    jp->LoadFromStream(pFluxImage); // charger le jpeg converti en bitmap
    C'est uniquement ce qui me manquait maintenant ça marche !!!!
    Je savais pas qu'il fallait le remettre à la position 0 pour que ça fonctionne.

    Pour le
    ->Read(&tab,2))
    Je compare des caractères (pas ascii): "ÿ"(=FF) par exemple est codé sur 2 octets et pas 1. C'est pour cela que j'ai mis 2.
    Par contre dans le strncmp j'aurai peut être pu mettre 1 au lieu de 2? ça marcherai autant je pense.

    Ça fait vraiment plaisir, ça faisait longtemps que je suis dessus ^^ merci encore pour tout j'aurai chercher peut être encore longtemps. bonne journée

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 02/09/2014, 15h11
  2. Réponses: 4
    Dernier message: 29/10/2010, 14h40
  3. récupérer une image avec readfile
    Par julien1451 dans le forum Langage
    Réponses: 11
    Dernier message: 27/01/2010, 01h06
  4. Récupérer taille d'une image avec IE
    Par olbouss dans le forum jQuery
    Réponses: 5
    Dernier message: 03/11/2009, 09h20
  5. Réponses: 4
    Dernier message: 07/06/2006, 14h23

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