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 :

Problème de lecture avec TServerSocket / TClientSocket [Web/Reseaux]


Sujet :

C++Builder

  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2011
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 56
    Par défaut Problème de lecture avec TServerSocket / TClientSocket
    Bonjour.

    Je réalise actuellement un programme devant communiquer à travers le réseau avec une autre application (codée en C++ / Qt).

    Ne connaissant pas trop Borland, j'ai cherché à apprendre comment communiquer en réseau. Je suis parti sur TServerSocket / TClientSocket. N'arrivant pas à lire correctement les données reçues, j'ai cherché un exemple sur le web et je suis tombé là dessus : http://cpp.developpez.com/telecharge...-un-petit-chat

    Mais je me retrouve avec le même problème, ce que le serveur lit n'a rien à voir avec ce qui est écrit par le client.

    Voici le code de la réception de donnée :
    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
     
    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
          TCustomWinSocket *Socket)
    {
      AnsiString  DataRecue = "",
                  Temp = "",
                  ChaineNom = "<Nom>";
      ItVecClients VecIterator;
      int HandleClient = 0;
     
      //Recevoir les données envoyées par un client
      DataRecue = Socket->ReceiveText();
     
      //Si c'est un client qui déclare son nom, alors le rajouter dans la liste
      if(DataRecue.Pos(ChaineNom) != 0)
      {
        Temp = DataRecue.SubString(ChaineNom.Length() + 1, DataRecue.Length());
     
        VecIterator = vecClients.begin();
        while(VecIterator != vecClients.end())
        {
          HandleClient = (*VecIterator).second;
     
          if(Socket->SocketHandle == HandleClient)
          {
            ListBox1->Items->Delete(ListBox1->Items->IndexOf((*VecIterator).first));
            ListBox1->Items->Add(Temp);
            (*VecIterator).first = Temp;
            break;
          }
     
          VecIterator++;
        }
      }
      else
      {
        MemoData->Lines->Add(DataRecue);
      }
    }
    Quand je tape "azerty", je me retrouve avec "????" en sortie.
    Auriez vous une idée du problème ?

    Merci d'avance pour votre aide !

    OkamiRyuu

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 081
    Par défaut
    Tu utilise le TServerSocket, C++Builder 6 ou XE2
    Ton problème de "????" c'est typique d'un problème Unicode ou de problème de CharSet !

    TServerSocket est un vieux composant, il est souvent remplacé par TTCPServer ou TIdTCPServer, personnellement pour l'avoir massivement utilisé, je n'ai jamais eu de problème en D5 et D6 !

    Utilise Telnet comme client pour débugguer !

    Si DelphiXE2, ReceiveText utilise le type AnsiString, j'ignore c'est très prudent, ils auraient dû plutôt utiliser RawByteString

    Par précaution, je l'utiliserais ReceiveBuf au lieu de ReceiveText avec un tableau de Byte et non des Char\AnsiChar\WideChar !
    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

  3. #3
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2011
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 56
    Par défaut
    Bonjour ShaiLeTroll, et merci de ta réponse.

    J'utilise Borland C++ Builder 2009.

    J'ai testé avec ReceiveBuf, mais le résultat semble le même . Tant qu'a TTCPServer ou TIdTCPServer, j'ai bien pensé à les utiliser, vu que TServeurSocket n'est plus très conseillé, mais je n'est trouvé que peu de chose sur le web les concernant.

    Comment Telnet, je viens de faire le test et le résultat est le même . Je vais remettre ReceiveBuf et faire le test ...

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 081
    Par défaut
    Tu peux me montrer ton code avec ReceiveBuf ?

    il est claire que tu as une conversion Unicode (2009 étant la première version Unicode de C++Builder)
    On dirait qu'il prend ta chaine Temp comme une donnée brute qu'il ne convertit pas en Unicode lors du Items->Add !

    Que donne, après Temp = DataRecue.SubString...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MessageBoxA(NULL, Temp.c_str(), "Debug", MB_OK + MB_ICONINFORMATION);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ShowMessage(IntToStr(StringCodePage(Temp)));
    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

  5. #5
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2011
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 56
    Par défaut
    Et ben mince alors ! En fait avec ... ça marche maintenant ! Je devais avoir plusieurs erreurs en même temps.

    Du coup, j'ai pu lire une chaine de caractère. Et j'ai aussi pu lire un entier sur 16bits. Seulement ... Dès que je souhaite lire les 2 dans une même trame, ça ne marche plus

    Voici le code du 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
     
    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
          TCustomWinSocket *Socket)
    {
      AnsiString  DataRecue = "",
    			  Temp = "",
    			  ChaineNom = "<Nom>";
      ItVecClients VecIterator;
      int HandleClient = 0;
      DataRecue.SetLength(Socket->ReceiveLength());
     
      //Recevoir les données envoyées par un client
      __int16 toto;
      char* buf;
     
      Socket->ReceiveBuf(&toto, 2);
      Socket->ReceiveBuf(buf, 3);
     
      // ...
    }
    Et voici le code du client:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void __fastcall TForm1::ButtonEnvoyerClick(TObject *Sender)
    {
        __int16 toto = 15;  
      //Envoyer des données au serveur
      if(ClientSocket1->Active == true)
      {
         ClientSocket1->Socket->SendBuf(&toto, 2); //sizeof(__int16) = 2
         char* var = new char[3];
         var = "aze";
         ClientSocket1->Socket->SendBuf(var, 3);
      }
    }
    Pourtant, l'ordre de lecture / écriture est bonne. Mais je récupère une erreur "classe d’exception ESocketError quand j'envoie un message. Une idée ?

    Encore merci pour votre aide !

  6. #6
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 081
    Par défaut
    Tu n'oublie pas d'allouer buf dans ServerSocket1ClientRead ?
    Et dans ButtonEnvoyerClick, tu n'as pas libérer var !
    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

  7. #7
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2011
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 56
    Par défaut
    Oui, en effet, il faut l'allouer ! Désolé de ne pas y avoir pensé, je suis partie sur ce que j'avais fait en Qt, et il n'est pas nécessaire de l'allouer avec QDataStream.

    Concernant var, si je le supprime juste après, ça me génère une erreur, surement parce qu'il est encore en train d'envoyer le message au moment de la suppression ...

    Merci beaucoup pour votre aide !!

  8. #8
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 081
    Par défaut
    En général, mon serveur ne lisait pas les données ainsi (moi je le faisais en Delphi)
    Dans OnClientRead, je lisais TOUT le buffer disponible !
    Comme ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
          TCustomWinSocket *Socket)
    {
      int Len = Socket->ReceiveLength();
      BYTE* buf = new BYTE[Len];
      Socket->ReceiveBuf(buf , Len);
     
      BuffersLock(); // Section Critique
      Buffers[Socket.Handle].Write(buf, Len);
      BuffersUnLock(); // Section Critique + Signal
    }
    Buffers était ma propre classe d'association, en c++, une Map<THandle, TMemoryStream*> fera l'affaire !

    Ensuite, un thread venant lire Buffer, pour l'analyser et le découper en message, ajouter à une TThreaList, avec un système d'ACK\NAK ainsi qu'une réponse !
    Il pouvait rester à la fin de buffer un message partiellement reçu, je recopiais la fin au début, et tronquait à la nouvelle taille, ainsi le socket pouvait continuer à ajouter ses buffers après le buffer restant !

    Tu devrais regarder ce sujet avec les Stream
    Socket et envoi d'image
    Envoi donnes par socket
    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

  9. #9
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2011
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 56
    Par défaut
    D'accord, je vais jeter un coup d'oeil à ça. En fait, mon serveur va envoyer beaucoup de données mais en recevoir très peu (la demande d’envoi, c'est tout). De plus, le format des messages est imposé et c'est le suivant :

    taille du message dans un __int16 suivi du message.

    Du coup, il n'est peut être pas nécessaire de lire tout d'un coup, non ?

  10. #10
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 081
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 : 14 081
    Par défaut
    Pense que si il reçoit beaucoup de données, plus vite tu les lis moins le risque de faire déborder le tampon TCP sera présent (teste, envoie 65K mais ne fait rien dans OnClientRead, à moment donné, tu as des pertes, bon mon TCP date Win98, NT4 et 2K, ça fait bien longtemps que j'en ai pas fait à la mano !)

    Moins l'on reste dans OnClientRead mieux c'est !

    On dirait un protocol Windev qui indique la longueur du buffer qui suit !
    En général, les machines avec lesquelles je dialoguais avait des protocoles avec marqueur début, marquer fin, longueur du message et type du message (parfois même un checksum), des messages très structurés pouvant contenir plusieurs items ... les protocoles étaient souvent des versions adapté au TCP de protocole de Terrain de Bus !

    Indy gère la taille automatiquement mais sur 4 ou 8 octets (selon option)

    Moi, je préfère lire le plus tôt possible, stocker la donnée en attente pour la parser dans un deuxième temps !
    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

  11. #11
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2011
    Messages
    56
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2011
    Messages : 56
    Par défaut
    La trame est celle que j'utilise côté Qt, en fait ! Je suis parti d'un tuto indiquant ce type de trame. Du coup, je suis resté là dessus.

    Concernant le serveur, oui, je comprend la nécessité de traiter les données dans un deuxième temps. Comme je ne reçois que peu de données, ce n'est peut être pas nécessaire, mais si j'ai le temps, je le ferais (je dois avouer que je ne suis pas très à l'aise avec Borland).

    En tout cas, merci pour ton aide précieuse !

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 11/05/2010, 09h27
  2. Problème de lecture avec les Socket
    Par Kevin12 dans le forum Entrée/Sortie
    Réponses: 2
    Dernier message: 18/03/2009, 15h40
  3. Problème de lecture avec un player audio ouvert par SWFobject
    Par ceddus dans le forum Balisage (X)HTML et validation W3C
    Réponses: 2
    Dernier message: 21/06/2007, 04h47
  4. [DEBUTANT] Problème de lecture avec un fscanf
    Par Pingouin dans le forum C
    Réponses: 26
    Dernier message: 28/05/2006, 18h10
  5. [DOM] Problème de lecture avec DOM
    Par samios dans le forum Format d'échange (XML, JSON...)
    Réponses: 5
    Dernier message: 29/09/2004, 15h58

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