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 :

Indy, 1 serveur, n clients


Sujet :

Web & réseau Delphi

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Mars 2006
    Messages : 147
    Points : 84
    Points
    84
    Par défaut Indy, 1 serveur, n clients
    Bonjour,

    Je ne maîtrise pas, loin s'en faut Indy. Je souhaite utiliser un serveur TCP pour une communication entre plusieurs process, 2 process clients, 1 process serveur, sur une même machine.

    J'ai donc un serveur (TIdTcpServer) et 2 clients (TIdTcpClient).

    L'idée est de créer un process serveur qui écoute sur 3 ports.
    Le port 1 est utilisé pour la connexion initiale quand un client se connecte, port sur lequel le serveur lui renvoie un n° de port disponible.
    Alors le client se déconnecte du port 1 et se reconnecte au port libre fourni précédemment.
    Le but est aussi que le serveur puisse réagir quand un client se déconnecte, donc la connexion est permanente sur les ports 2 et 3 et du code est exécuté sur le serveur dans le "OnDisconnect" du serveur.

    Pour schématiser on a SRV, CLT1, CLT2. On ne peut pas prédire si CLT1 démarre avant CLT2 ou inversement, et on veut pouvoir prévoir d'autre process clients si nécessaire à l'avenir.
    SRV écoute sur les ports 1, 2 , 3
    CLT1 démarre, se connecte au port 1, SRV lui renvoie le port libre 2, CLT1 se déconnecte du port 1 et se reconnecte au port 2 de façon permanente.
    CLT2 démarre, se connecte au port 1, SRV lui renvoie le port libre 3, CLT2 se déconnecte du port 1 et se reconnecte au port 3 de façon permanente.

    Est-ce une bonne approche ? Ou existe-t-il déjà un mécanisme similaire dans Indy ?

    J'ai commencé à expérimenté. La communication entre SRV et CLT1 est ok.
    En revanche, bien que le port 1 soit déconnecté, la connexion du client suivant CLT2 sur le port 1 semble poser problème.
    La connexion n'est pas refusée, mais elle semble échouer après le timeout fixé. Que ce timeout soit de 500ms ou de 10 secondes ne change rien.

    Code de connexion d'un 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
    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
     
    function TMes.Conn() : Boolean;
    const sname = 'TMes.Conn';
    var NewPort : Word;
         SocketResponse : TSocketMsg;
    Begin
            result := false;
     
            clt.Connect; // Connexion au port 1
            if IsCltConnected(Clt) then begin
     
              clt.IOHandler.WriteLn(SocketMsg(tcpGetPort, '', true).Str); // Demande de port libre
              SocketResponse := SocketMsg(clt.IOHandler.ReadLn);      // Lecture du port fourni
     
              if clt.IOHandler.ReadLnTimedout then begin
                trace(logOnDebug, sname,'TIMEOUT CAS 1'); // Timeout : C'est un des deux traces que je trouve dans mon log quand CLT2 tente de se connecter...
              end;
     
              if SocketResponse.ok then begin
                NewPort := StrToInt(SocketResponse.What);
                clt.IOHandler.InputBuffer.clear;
                clt.Disconnect; // Déconnexion port 1
     
                clt.Port := NewPort;
                clt.Connect; // Reconnexion au port fourni
     
                if IsCltConnected(Clt) then begin
                  Clt.IOHandler.WriteLn(SocketMsg(tcpGetProcess, '', true).Str);
                  try
                    SocketResponse := SocketMsg(clt.IOHandler.ReadLn);
     
                    if clt.IOHandler.ReadLnTimedout then begin
                      trace(logOnDebug, sname,'TIMEOUT CAS 2'); // ..Ou c'est parfois celle-ci
                    end;
     
                    if SocketResponse.ok then begin                    
                        result := true;
                    end
                    else begin
                        clt.IOHandler.InputBuffer.clear; 
                        clt.Disconnect;  
                    end;
                 except
                    on e: Exception do begin
                      clt.IOHandler.InputBuffer.clear; // Sinon pas de déconnexion !
                      clt.Disconnect(false);
                    end;
                  end;
                end
                else begin
                  trace(logOnDebug, sname,'Connexion impossible');
                end;
              end
              else begin
                trace(logOnDebug, sname,'Réponse invalide, déconnexion');
                clt.IOHandler.InputBuffer.clear; // Sinon pas de déconnexion !
                clt.Disconnect;
              end;
            end;
    end;
     
    function TMes.IsCltConnected (var Clt : TIdTcpClient) : boolean;
    const sname = 'TMes.IsCltConnected';
    begin
        result := false;
        try
          result := clt.Connected;
        except
          on e : exception do begin
            try
              // Dans ce cas on passe False => on ne notifie pas la peer de la déconnexion puisque la peer est morte.
              clt.Disconnect(False);
            except
              on e : exception do begin
                trace(logOnRelease, sname,'==========================> EXCEPTION : '+ e.Message);
              end;
            end;
            if assigned(clt.IOHandler) then clt.IOHandler.InputBuffer.Clear;
          end;
        end;
    end;
    Code côté 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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
     
    procedure TMes.TcpSrvExecute(AContext: TIdContext);
    const sname = 'TMes.TcpSrvExecute';
    Var i : integer;
        Msg, Response : TSocketMsg;
    begin
     
     
        Msg := SocketMsg(AContext.Connection.IOHandler.ReadLn);
     
        // Initialisation réponse : Qu'on enverra que si Msg.Wait
        Response := SocketMsg(tcpKo, '', false);
     
        trace(logOnRelease, sname,'Réception de ' + Msg.Str + ' Who=' + Msg.Who + ' Why=' + Msg.Why + ' What='+Msg.What + ' Wait='+StrLog(Msg.Wait));
     
     
        // Demande de port
        if Msg.Why = tcpGetPort then begin
          trace(logOnDebug, sname,'Demande de port');
          for i := 2 to tcpNbPort do begin // Port 1 = broker
            if not PortInUse[i].Used then begin
              PortInUse[i].Used := true;
              Response := SocketMsg(tcpOk, IntToStr(PortInUse[i].Port), false);
              break;
            end
            else begin
              trace(logOnDebug, sname,'Port ' + IntToStr(PortInUse[i].Port) + ' occupé');
            end;
          end;
        end
     
        // Demande de nom de process pour contrôle
        else if Msg.Why = tcpGetProcess then begin
          trace(logOnDebug, sname,'Demande de Process');
          Response := SocketMsg(tcpOk,GetWinProc(WHO_AM_I), false);
        end
     
        else begin
           trace(logOnDebug, sname,'TcpSrvExecute - "Why" inconnu ' + Msg.Why + ' What=' + Msg.What);
        end;
     
        // Renvoi ack et réponse
        if Msg.Wait then begin
          trace(logOnDebug, sname,'Renvoi de ' + Response.Str +
                               ' Who=' + Response.Who +
                               ' Why=' + Response.Why +
                               ' What='+ Response.What +
                               ' Wait=' + StrLog(Response.Wait));
          AContext.Connection.IOHandler.WriteLn(Response.Str);
        end;
    end;

    (Remarque : TMes = class(TThread))

    Y-a-t-il un problème de déconnexion ? Ou est-ce un problème lié au fait que le CLT1 restant connecté au port 2, le SRV ne peut pas prendre en compte les demandes du CLT 2 ?

    Merci pour vos retours.

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Mars 2006
    Messages : 147
    Points : 84
    Points
    84
    Par défaut
    Bien, après quelques investigations, le problème était au niveau du Thread TMes lui-même : Dans le 'OnExecute' du serveur TCP, il y avait un Lock.
    Du coup, aucun autre 'OnExecute' n'était exécuté tant que le premier client n'était pas déconnecté.
    J'ai revu mon code pour évité ce problème et tout fonctionne.

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

Discussions similaires

  1. [Indy 10] Serveur FTP avec SSL
    Par KarMa_CoMa dans le forum Web & réseau
    Réponses: 5
    Dernier message: 21/04/2005, 09h51
  2. Réponses: 4
    Dernier message: 16/08/2004, 17h03
  3. Client-Serveur Dcom = Client+Serveur lancés sur la machine ?
    Par Jilam dans le forum Bases de données
    Réponses: 6
    Dernier message: 27/07/2004, 14h55
  4. Serveur Multi-clients
    Par darsky dans le forum C++Builder
    Réponses: 5
    Dernier message: 16/04/2004, 09h53
  5. Création d'un Serveur Multi Client
    Par N*E*R*D dans le forum Autres éditeurs
    Réponses: 5
    Dernier message: 16/03/2004, 17h13

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