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 :

IdTCPServer sans Form visible


Sujet :

Web & réseau Delphi

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2013
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2013
    Messages : 6
    Points : 7
    Points
    7
    Par défaut IdTCPServer sans Form visible
    Bonjour à tous,

    J'ai créé une application serveur, en utilisant le composant IdTCPServer sans Form visible qui reste active grâce à une boucle infinie.
    Ma question est donc la suivante : existe t-il un moyen de faire tourner un serveur de type IdTCPServer sans Form visible et sans boucle infinie ?
    Si oui, avez-vous un exemple ?

    Merci de vos réponses.

  2. #2
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 961
    Points
    6 961
    Par défaut
    Un service ?
    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    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 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Sur un executable normale, impossible de se passer de la boucle infinie (comme celle du Application.Run )
    Le Service comme le suggère Lung est tout à fait pertinent,
    un peu plus chiant à débugguer mais tout à fait fonctionnel,
    Si tu te débrouilles bien, tu peux faire un EXE normal pour le débogage, un autre EXE Service pour la PROD
    A part, l'utilisation du Journal via TService.LogMessage que l'on ne peut pas utiliser en EXE normal, il y a pas de grande différence en terme de code
    Juste ne jamais utilisé de TForm, ni de Dialogs !

    personnellement, je l'utilise mais pour TServerSocket en mode full thread :
    • un thread pour le listen
    • un thread par client connecté, au plus 20
    • un thread de file d'attente des messages (reçus par les TWinSocketStream) traités en FIFO
    • un thread de traitements des message et des opérations sur le Base de Données
    • un thread pour le TIdFTPServer intégré
    • un thread de notification inter-process (envoie vers les modules connectés via un TClientSocket)
    • un thread de notification par mail (monitoring)
    • un thread de surveillance de dossier et récupération de fichier
    • un thread d'envoi de fichier


    Sinon, la boucle infinie n'a rien de grave si elle codée via l'attente de message, cela coute 0% CPU d'attendre les messages,
    voici une variante pour le TServerSocket

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    program Server;
     
    uses
      ServerApplicationClasses in 'ServerApplicationClasses.pas';
     
    {$R *.res}
     
    begin
      RunServer();
    end.
    Le TServerSocket est en mode stNonBlocking dans cet exemple
    Donc au lieu d'utiliser des Threads et des TWinSocketStream, cela utilise le message Windows pour déclencher les Events !

    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
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
     
    unit ServerApplicationClasses;
     
    interface
     
    uses
      Windows, SysUtils, Messages, StrUtils, ScktComp;
     
    type
      TServerApplication = class(TObject)
      private
        FServerSocket: TServerSocket;
        FServerTerminated: Boolean;
        FConnectCount: Integer;
        FReadCount: Integer;
        FReadCharCount: Integer;
     
        procedure ClientConnectEventHandler(Sender: TObject; Socket: TCustomWinSocket);
        procedure ClientReadEventHandler(Sender: TObject; Socket: TCustomWinSocket);
        procedure ClientDisconnectEventHandler(Sender: TObject; Socket: TCustomWinSocket);
     
      public
        constructor Create();
        destructor Destroy; override;
     
        procedure Run();
      end;
     
    procedure RunServer();
     
    implementation
     
    //---------------------------------------------------------------------------
    procedure RunServer();
    begin
      with TServerApplication.Create() do
      try
        Run();
      finally
        Free();
      end
    end;
     
    //---------------------------------------------------------------------------
    constructor TServerApplication.Create();
    begin
      inherited Create();
     
      FServerSocket := TServerSocket.Create(nil);
      FServerSocket.Port := 12345;
      FServerSocket.ServerType := stNonBlocking; // C'est le plus simple à gérer !
      FServerSocket.OnClientConnect := ClientConnectEventHandler;
      FServerSocket.OnClientRead := ClientReadEventHandler;
      FServerSocket.OnClientDisconnect := ClientDisconnectEventHandler;
    end;
     
    //---------------------------------------------------------------------------
    destructor TServerApplication.Destroy();
    begin
      FreeAndNil(FServerSocket);
     
      inherited Destroy();
    end;
     
    //---------------------------------------------------------------------------
    procedure TServerApplication.Run();
    var
      Msg: TMsg;
    begin
      FServerSocket.Open();
     
      while not FServerTerminated do
      begin
        if WaitMessage() then
        begin
          if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
          begin
            case Msg.message of
              WM_QUIT :
                FServerTerminated := True;
     
              CM_SOCKETMESSAGE,
              CM_DEFERFREE,
              CM_LOOKUPCOMPLETE :
                DispatchMessage(Msg);
            end;
     
            if (FConnectCount > 0) and (FServerSocket.Socket.ActiveConnections = 0) then
              FServerTerminated := True;
          end
        end
        else
          FServerTerminated := True;
      end
    end;
     
    //---------------------------------------------------------------------------
    procedure TServerApplication.ClientConnectEventHandler(Sender: TObject; Socket: TCustomWinSocket);
    begin
      OutputDebugString(PChar('Connect : ' + Socket.RemoteAddress));
      Inc(FConnectCount);
      Socket.SendText(Socket.RemoteAddress + ' : your are connection N°' + IntToStr(FConnectCount) + sLineBreak);
    end;
     
    //---------------------------------------------------------------------------
    procedure TServerApplication.ClientReadEventHandler(Sender: TObject; Socket: TCustomWinSocket);
    var
     Buf: String;
     CharCount: Integer;
    begin
      Buf := Socket.ReceiveText();
      CharCount := Length(Buf);
      Inc(FReadCharCount, CharCount);
      Inc(FReadCount);
      Socket.SendText(Socket.RemoteAddress + ' : server have receive ' + IntToStr(CharCount) + ' chars [total : ' + IntToStr(FReadCharCount) + ' chars, ' + IntToStr(FReadCount) + ' packets]' + sLineBreak);
     
      if (CharCount = 1) then
      begin
        if Ord(Buf[1]) = VK_ESCAPE then
          Socket.Close();
      end
      else
        if AnsiContainsText(Buf, 'STOP') then
          FServerTerminated := True;
    end;
     
    //---------------------------------------------------------------------------
    procedure TServerApplication.ClientDisconnectEventHandler(Sender: TObject; Socket: TCustomWinSocket);
    begin
      OutputDebugString(PChar('Disconnect : ' + Socket.RemoteAddress));
    end;
     
    end.
    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
    Futur Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2013
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Octobre 2013
    Messages : 6
    Points : 7
    Points
    7
    Par défaut
    Merci à vous deux de vos réponses. Je vais me pencher sur les services et je vous tiendrai au courant.

  5. #5
    Membre expert
    Avatar de LadyWasky
    Femme Profil pro
    Inscrit en
    Juin 2004
    Messages
    2 932
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 53
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    Points : 3 565
    Points
    3 565
    Par défaut
    Un IdTCPServer maintenu actif, ok , pas de soucis, on ouvre la connexion (Open), mais grâce à une boucle infinie ??? Nan, jamais vu, il y a un truc qui cloche dans le "design" de votre appli.

    Le déclenchement des actions se fait par un évènement système qui appelle une fonction de type Callback, point barre, il n'y aucun code qui tourne en boucle infinie pendant l'attente, j'comprends pas...

    Elle ressemble à quoi votre boucle infinie ? Je suis curieuse et interrogative et entrevois une incompréhension de votre part de comment fonctionne un composant réseau : ne me dite pas que vous faites une boucle sur IdTCPServer.Open, parce qu'a chaque fois que vous envoyez ou recevez des donnez vous faites un IdTCPServer.Close; !
    Bidouilleuse Delphi

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    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 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Citation Envoyé par LadyWasky Voir le message
    Un IdTCPServer maintenu actif, ok , pas de soucis, on ouvre la connexion (Open), mais grâce à une boucle infinie ??? Nan, jamais vu, il y a un truc qui cloche dans le "design" de votre appli.:
    Dans une application Windows c'est TApplication.Run() qui fait la boucle !
    Si tu ne mets pas de boucle Wait/PeekMessage, l'application s'arrête, il a peut-être fait comme dans le code que j'ai proposé un remplacement total du TApplication par une autre classe et dans ce cas, il faut écrire soit même la boucle

    Du moins, j'espère que c'est bien cela !
    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 expert
    Avatar de LadyWasky
    Femme Profil pro
    Inscrit en
    Juin 2004
    Messages
    2 932
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 53
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    Points : 3 565
    Points
    3 565
    Par défaut
    Oui en effet, mais c'est bien la seule boucle infinie existante apparaissant dans une application Delphi.
    Bidouilleuse Delphi

  8. #8
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 683
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 683
    Points : 13 092
    Points
    13 092
    Par défaut
    Citation Envoyé par LadyWasky Voir le message
    Oui en effet, mais c'est bien la seule boucle infinie existante apparaissant dans une application Delphi.
    On peut en avoir une par thread.

  9. #9
    Membre expert
    Avatar de LadyWasky
    Femme Profil pro
    Inscrit en
    Juin 2004
    Messages
    2 932
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 53
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    Points : 3 565
    Points
    3 565
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    On peut en avoir une par thread.
    J'y ai pensé aussi, mais en fait on peut s'en passer dans les thread la plupart du temps. La boucle infinie, c'est rare dans les threads.
    Bidouilleuse Delphi

  10. #10
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 683
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 683
    Points : 13 092
    Points
    13 092
    Par défaut
    Il n'y en a pas si le thread exécute une action unique mais il y en a une s'il est démarré périodiquement (par Event) ou qu'il sert de récepteur à des messages externes (GetMessage).
    Mais rare en tout cas pas. Je dirais même que j'en utilise plus avec que sans

  11. #11
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 447
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    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 447
    Points : 24 849
    Points
    24 849
    Par défaut
    Idem, mes threads hérités sont tous en boucle infinie à base de TEvent, WaitData, WaitMessage ... il passe 99% du temps à ne rien faire qu'à attendre le signal qui indique qu'il y a un élément dans une TThreadList ou qu'il faut éventuellement lancé un traitement en cas trop long délai d'inactivité, ou alors un traitement à période fixe.

    ce qui donne ceci

    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
    53
    54
    55
    56
    57
    procedure TThreadHérité.Execute();
    var
      wr: TWaitResult;
    begin
      while not Terminated do
      begin
        wr := FSignal.WaitFor(FDelay);
        case wr of
          wrSignaled:
            begin
              if not Terminated then
                TraitementDeLaFileDAttente();
            end;
     
          wrTimeout:
            begin
              if not Terminated then
                Idle();
            end;
        end;
      end;
     
      Purge();
    end;
     
    //------------------------------------------------------------------------------
    function TThreadHérité.AddBidule(Bidule: TTruc): Boolean;
    var
      ItemPtr: PFile;
    begin
      Result := False;
     
      if not Terminated and Assigned(FFileDAttente) and Assigned(FSignal) then
      begin
        New(ItemPtr);
        try
          ItemPtr^ := Bidule; // ici on recopie le paramètre complètement 
          FFileDAttente.Add(ItemPtr);
          Result := True;
        except
          Dispose(ItemPtr);
        end;
     
        if Result then
          FSignal.SetEvent()
      end;
    end;
     
     
    //------------------------------------------------------------------------------
    procedure TThreadHérité.TerminatedSet();
    begin
      inherited TerminatedSet();
     
      if Assigned(FSignal) then
        FSignal.SetEvent(); // Arrêt prématuré !
    end;
    En fait, maintenant pour un thread one shot, autant faire une méthode anonyme via TThread.CreateAnonymousThread
    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. Rendre une form visible avant de la minimiser
    Par WebPac dans le forum API, COM et SDKs
    Réponses: 9
    Dernier message: 29/03/2006, 17h16
  2. Touche sans form
    Par petitcoucou31 dans le forum Composants VCL
    Réponses: 1
    Dernier message: 08/02/2006, 00h56
  3. rendre une form visible sans lui donner le focus
    Par kchrel dans le forum Access
    Réponses: 4
    Dernier message: 24/01/2006, 15h37
  4. Utilisation de composant sans Form est elle possible
    Par Hypollite76 dans le forum Composants VCL
    Réponses: 26
    Dernier message: 01/12/2005, 12h07
  5. composant visible sans forme précise. Avez vous un miracle ?
    Par yoghisan dans le forum Composants VCL
    Réponses: 5
    Dernier message: 10/02/2004, 00h29

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