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

Web & réseau Delphi Discussion :

[Delphi 7] Utilisation des composants Indy TCPServer et TCPClient


Sujet :

Web & réseau Delphi

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    174
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 174
    Points : 38
    Points
    38
    Par défaut [Delphi 7] Utilisation des composants Indy TCPServer et TCPClient
    Bonjour,

    J'ai codé une 2 petites applications Delphi 7 de test pour apprendre à bien utiliser les composant Indy TIdTCPServer et TIdTCPClient.
    Les 2 applications sont très simples et fonctionnent à peu près. Comme vous vous en doutez, c'est le "à peu près" qui me gêne.

    En fait je pense ne pas avoir bien compris certains concepts de ces composants, notamment la propriété Bindings du composant TIdTCPServer.

    Le problème que je rencontre avec mes 2 executables est le suivant : je lance le serveur, puis je lance le client. Quand je clique sur le bouton "Connect" de mon client, tout se passe bien.
    Par contre, si je clique sur le bouton "Disconnect" du client puis qu'ensuite je clique sur le bouton "Connect", j'ai une exception qui se déclenche : "Address already in use".

    Je ne comprends pas du tout ce qui se passe.

    J'ai mis en pièce jointe le code des 2 applications.

    Si quelqu'un peut y jeter un oeil...

    Merci d'avance.
    Fichiers attachés Fichiers attachés

  2. #2
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    en IP v4, un serveur est identifié par un @IP et un numéro de port (le binding), sur une même machine je peux avoir différents serveurs sur différents ports

    quand on tente de faire un binding sur un port déjà utilisé on a l'erreur "Address already in use"

    je suis surpris que tu puisses avoir cette erreur au niveau client, car généralement on ne définie pas de Binding au niveau client; un numéro de port aléatoire est attribué automatique (car on a toujours un numéro de port, y compris pour le client, car lui aussi peut faire plusieurs connexions en même temps depuis la même adresse, c'est le port qui va permettre de savoir qui fait la requête)
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 455
    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 455
    Points : 24 867
    Points
    24 867
    Par défaut
    Je n'ai pas regardé le Zip, Indy 9 par défaut de Delphi 7 ?
    Je n'ai pas du tout aimé ces composants à l'époque

    Un test simple, un telnet, comme se comporte-t-il lorsqu'il se connecte sur le serveur ?

    Pour Bindings, en local, avec le TIdFTPServer (hérite du TIdTCPServer), je me souviens que ça ralait, j'ignore si c'est valable.
    C'était uniquement en localhost que ça provoquait une erreur côté client de ce type lorsque j'avais un client Delphi + FileZilla dessus

    EDIT, je confirme, le dernier TIdTCPServer que j'ai codé pour que ça déconne pas en local, j'ai ajouté ça

    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
    procedure TEtiquetteServeur.InitServeurTCP();
    begin
      WebServerTCP.Bindings.Clear();
      with WebServerTCP.Bindings.Add() do 
      begin
        IP := '0.0.0.0';
        Port := GUEST_CLIENT_PORT_TCP;
      end;
      WebServerTCP.OnExecute := WebServerTCPExecute;
      WebServerTCP.Active := True;
    end;
     
    procedure TEtiquetteServeur.InitServeurHTTP;
    begin
      {  TIdHTTPServer.KeepAlive
       propriété), mais ce n’est toujours pas une garantie. Le client, ou un proxy / routeur
       entre le client et le serveur, peut toujours fermer la connexion à tout moment.  }
      //WebServerHTTP.KeepAlive := True;
      WebServerHTTP.OnCommandGet := FIdHTTPServerCommandGet;
      WebServerHTTP.OnConnect  := CustomOnConnect;
      WebServerHTTP.MaxConnections := 20;
      with WebServerHTTP.Bindings.Add() do 
      begin
        IP := '0.0.0.0';
        Port := GUEST_CLIENT_PORT_HTTP;
      end;
      WebServerHTTP.Active := True;
    end;
    WebServerTCP et WebServerHTTP sont créés dynamiquement dans un Service Windows, pas de TForm.
    C'est une sorte de routeur, des programmes abonnés TCP attendent des ordres et d'autres programmes envoient des ordres en HTTP, le serveur lui va router les ordres vers l'abonné cible et cela entre la France, la Chine, l'Inde ... un jour faudrait que je demande comment ça tient les milliers d'ordre journalier, une collègue et moi avions développé cela peut de temps avant de partir ...

    Note donc qu'il y a bien deux serveurs sur deux ports différents sans problème
    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
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    174
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 174
    Points : 38
    Points
    38
    Par défaut
    Je pense avoir résolu mes problèmes.
    En fait, j'ai simplifié pas mal les choses : je n'utilise plus la propriété "Binding" sur le composant TIdTCPServer et côté TIdTCPClient, je n'utilise plus non plus les propriétés "BoundIP" et "BoundPort".

    Je joins la nouvelle version de mon code pour ceux que ça intéresse.
    Fichiers attachés Fichiers attachés

  5. #5
    Membre du Club

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2012
    Messages
    58
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Bénin

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2012
    Messages : 58
    Points : 43
    Points
    43
    Billets dans le blog
    1
    Par défaut
    N'hesitez pas à clore la discussion, si vôtre problème a été résolu !!! Cordialement !!

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    174
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 174
    Points : 38
    Points
    38
    Par défaut
    Bonjour à tous,

    En fait, j'ai encore quelques soucis avec les composants Indy.
    Je ne sais pas trop comment arrêter proprement mon serveur TCP.

    J'ai ajouté le code suivant sur l'evenement "OnClick" du bouton "Stop 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
     
     
    {-------------------------------------------------------------------
      Gestion du click sur le bouton "Stop Serveur"
    -------------------------------------------------------------------}
    procedure TServer_Form.Stop_Server_ButtonClick(Sender: TObject);
    begin
      if not TCP_Server.Active then Exit;
      try
        TCP_Server.Active := False;
      except
        On E:Exception do
          Begin
           ListBox2.Items.Add('Arret du serveur, Error : ' +  E.Message);
          End;
      end;
    end;
    Mais quand j'ai des clients connectés sur le serveur, j'ai l'exception "Terminate Thread timeout" qui se déclenche.
    Du coup, je ne sais pas trop comment stopper proprement mon serveur.
    Faut-il au préalable que je boucle sur tous les threads clients et que je les deconnecte?

    D'ailleurs l'autre question que je me pose, c'est comment fermer proprement mon application quand j'ai encore des connexions actives sur mon serveur ?

  7. #7
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    1) alors couper la connexion du serveur implique qu'il n'est plus à l'écoute du port sélectionné...mais tous les clients connectés sont actuellement sur un autre port, et stopper le serveur n'implique pas de couper les clients actifs (en fait je ne sais pas si TidTCPServer le fait ou pas)

    2) quand l'application se ferme, tous les sockets sont fermés, donc à part se préoccuper de faire les choses "proprement" ça n'a pas bcp d'importance

    ensuite, vu que tu sembles utiliser ton propre protocole de communication, tu peux très bien envoyer un ordre de déconnexion à tous tes clients quand tu veux fermer le serveur, ça permet à la partie client de gérer une coupure du serveur propre sans se demander pourquoi il n'est plus connecté.

    sur un serveur RESTfull je me contente de sauvegarde les identifiants de sessions actives avant fermeture, et je les relit au lancement, ce qui me permet de mettre à jour l'appli serveur sans perturber les sessions Web, c'est assez cool en fait et comme c'est du RESTfull je n'ai pas de connexion permanente (sauf des WebSocket mais c'est autrechose encore), les clients ne voient même pas l'interruption de service
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    174
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 174
    Points : 38
    Points
    38
    Par défaut
    Le soucis en fait c'est que le composant TidTCPServer semble buggué.
    Quand je désactive le serveur TCP:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TCP_Server.Active := False;
    ,
    mes clients sont bien déconnectés (pour info, je simule mes clients avec l'outil Hercule https://www.hw-group.com/software/he...-setup-utility).
    Par contre, l'arrêt du serveur part en timeout.
    Du coup, impossible d'arrêter/redémarre le serveur TCP.

    Sinon, j'ai essayer de regarder les composants TcpServer et TcpClient qui sont fournis avec Delphi 7 dans la palette d'outil (rubrique "Internet").
    Mais là, impossible de garder une connexion active avec un client.

    Mon besoin est d'avoir un serveur TCP sur lequel un client puisse rester connecté afin que le serveur TCP puisse lui envoyer des données.

  9. #9
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 455
    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 455
    Points : 24 867
    Points
    24 867
    Par défaut
    TTcpServer et TTcpClient de D7, ils ont remplacé le TServerSocket et TClientSocket pendant un moment
    Tu as déjà commencé par les exemples fournis, NetChat en D7 utilise TTcpServer et TTcpClient
    Préfère le mode ThreadBlocking et une gestion manuelle des threads que la version Event qui ne m'avait pas convaincu à l'époque

    Tu notes un bug ou un comportement que tu n'attendais pas mais pense que tu utilises D7 de 2002 et surement Indy9 qui a été abandonné au profit de Indy10 qui a justement revu beaucoup d'élément de TIdTCPServer sur la gestion des Threads par exemple.

    Perso, je suis revenu depuis XE2 à TServerSocket et TClientSocket pour l'IP car je me suis fait depuis D5 tout plein d'outil de dessus et que je maitrise bien mieux dessus les threads (TSLTRemoteMessenger) mais ce n'est pas une solution générique, c'est mon propre protocole d'échange de donnée et c'est le serveur qui notifie plus souvent qu'il ne reçoit d'ordre dans la dernière utilisation faite (pilotage + monitoring robot)

    Je me suis donc remis au TIdTCPServer\Client mais en Indy10 de DXE2, ainsi que que TIdHTTPServer\Client, l'arrêt du serveur fonctionnait de mémoire dans la version service, la version GUI était pour le débug et un peu moins rigoureuse.


    Cependant, je maintiens une application qui contient, plusieurs Server, TCP, UPD en Indy, encore plus de client TCP, UDP, FTP, SMTP, HTTP toujours en Indy, j'ai une erreur "connection reset by peer" ce qui est logique et le relancement est tout à fait possible

    Mais après, tu peux aussi instancier et libérer ton TIdTCPServer lorsque celui-ci n'est pas utile, ça devrait nettoyer tout ce qui traine
    De faire une classe d'encapsulation totalement séparée et isolée, sans lien direct à une TForm.
    En fait, c'est ce que je fais, l'objet TIdTCPServer , je le libère dès qu'il n'est plus utile.



    Au fait pourquoi D7 ?
    Pourquoi TCP
    Comme le fait remarquer Paul Toth, un server HTTP tel qu'un Service REST, peu souvent suffir pour des requêtes ponctuelles.
    Alors que le TCP, c'est idéal pour une connexion et un dialogue permanent ou dans le cadre de notification, c'est à dire c'est le Server qui émet à sa volonté un message aux clients abonnés.
    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

  10. #10
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    174
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 174
    Points : 38
    Points
    38
    Par défaut
    OK.
    J'avoue que c'est un peu la foire tous ces composants différents pour utiliser des sockets en Delphi 7 (d'ailleurs les TServerSocket et TClientSocket ne sont pas dans la palette de Delphi 7 mais sont bien présents dans les sources)
    Du coup, je pense que je vais rester sur les composants Indy 9 qui me semblent être les plus simples d'utilisation pour ce que je veux faire, même si je ne maitrise pas tout.

    Sinon, j'utilise Delphi 7 car je dois intégrer un serveur TCP dans une appli delphi 7 existante pour communiquer avec une autre application codée en C.

  11. #11
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 455
    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 455
    Points : 24 867
    Points
    24 867
    Par défaut
    Si c'est une fonctionnalité qui n'est pas systématique, un cas particulier pour un client, l'intégrer dans une DLL ou un Exe autonome pourrait avoir son intérêt.

    Faudrait que je creuse un jour pour que mon TSLTRemoteMessenger supporte Indy aussi et pourquoi pas D7 pour l'exercice Unicode\Ansi et la cohabitation de version, ça me servira pour mon taf actuel ou le TIdTCPServer est crucial.

    EDIT
    Sur Indy9 de D7
    TerminateAllThreads peut provoquer une EIdTerminateThreadTimeout si ça dépasse TerminateWaitTime par défaut à 5000ms
    Tu n'aurais pas du code bloqué dans le OnExecute qui bloquerait l'arret des TIdPeerThread ?
    Genre le IOHandler qui attend indéfiniment comme un ReadLn qui ne trouve jamais la fin
    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

Discussions similaires

  1. [Lazarus] Installation et utilisation des composants Indy sous Ubuntu
    Par tuxy dans le forum Lazarus
    Réponses: 13
    Dernier message: 03/06/2015, 14h14
  2. Réponses: 2
    Dernier message: 10/03/2014, 11h56
  3. Réponses: 0
    Dernier message: 03/04/2013, 11h33
  4. Utilisation des composants Indy
    Par pduceux dans le forum Delphi
    Réponses: 1
    Dernier message: 11/05/2007, 20h45
  5. Compilation des composants Indy 10
    Par rconty dans le forum C++Builder
    Réponses: 23
    Dernier message: 13/07/2005, 15h48

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