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 :

Détection câble coupé TServerSocket


Sujet :

Web & réseau Delphi

  1. #1
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Avril 2011
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 51
    Points : 50
    Points
    50
    Par défaut Détection câble coupé TServerSocket
    Bonjour,
    je voudrais améliorer mon appli client pour qu'elle détecte quand le server est arrêté brutalement ou quand le câble réseau sur machine Serveur est déconnecté.
    (j'ai deux clients (TClientSocket sur 2 ordis XP) et un server (TServerSocket sur 1 troisieme ordi XP))

    J'ai cherché et trouvé différents exemple de programme mais je n'arrive pas à les adapter pour mon cas.
    Il faudrait pouvoir faire un ping a intrevalles réguliers ?


    Merci D'avance pour les conseils.

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 454
    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 454
    Points : 24 866
    Points
    24 866
    Par défaut
    Ce sujet devrait te plaire : ServerSocket Comment vérifier si un client est connecté
    J'y évoque juste le TCP Keep Alive sur un TidTCPServer
    Note que les développeurs Indy ont appelé leur méthode SetSockOpt en référence à l'API MS setsockopt

    Pour un TServerSocket utilise son Handle et l'API setsockopt \ SO_KEEPALIVE ou l'API
    WSAIoctl \ SIO_KEEPALIVE_VALS

    Pour ma part, j'utilise mon propre système de Keep Alive
    Tout est bassé sur le Delay du TWinSocketStream.WaitForData dans le Execute du TServerClientThread
    Si je n'ai pas de Data au bout du Délai (60s dans mon cas), je fais mon Keep Alive

    En cas d'erreur du SendStream du TWinSocketStream
    Cela loggue dans un journal, la perte de la connexion et je retire le socket de mes tableaux internes
    Je n'ai pas encore osé de faire un Close du Socket

    Mais en général, dans mon objet hérité de TServerClientThread, j'utilise un objet hérité de TWinSocketStream utilisant son TClientWinSocket
    Lors d'une déconnexion, le TWinSocketStream.WaitForData renvoie True et le Read renvoie 0, dans cette situation, je fait un Close du Socket

    J'avoue ne pas avoir testé énormément la déconnexion sauvage, je le fais uniquement via CTRL+F2 en mode debug donc en local sur le poste
    En réseau, je crois que cela fonctionne moins bien

    ---------------------------
    Notification des exceptions du débogueur
    ---------------------------
    Le projet xxx.exe a déclenché la classe d'exception ESocketError avec le message 'Lecture erreur 64, Le nom réseau spécifié n’est plus disponible'.
    ---------------------------
    Après cela passe dans le OnDisconnect car dans le Execute du TServerClientThread, en cas d'Exception du TWinSocketStream.Read, je fais explicitement un Close du Socket

    D'ailleurs une version de mon composant TSLTRemoteMessenger traine ici ou là aussi
    La responsabilité de faire un KeepAlive est déporté à la classe utilisatrice qui doit fournir un gestionnaire du OnIdle
    comme par ce RemoteMessageIdleEventHandler
    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
     
    //------------------------------------------------------------------------------
    class procedure Txxx.RemoteMessageIdleEventHandler(Sender: TObject; AIdleSocket: TRemoteMessageSocketHandle);
    begin
      // Que faire en cas d'échec du KeepAlive ?
      if not RemoteMessageSystemKeepAlive(AIdleSocket) then
        if Assigned(FOnKeepAliveError) then
          FOnKeepAliveError(AIdleSocket);
    end;
     
    //------------------------------------------------------------------------------
    class function Txxx.RemoteMessageSystemKeepAlive(ATarget: TRemoteMessageSocketHandle = 0): Boolean;
    var
      rmska: TRemoteMessageSystemKeepAlive;
    begin
      rmska.TimeStamp := Now();
      Result := RemoteMessageSystem(rmstKeepAlive, @rmska, SizeOf(rmska), ATarget);
    end;
     
    //------------------------------------------------------------------------------
    class function Txxx.RemoteMessageSystem(ASystemType: TRemoteMessageSystemType; ASystemData: Pointer; ASystemDataLen: Integer; ATarget: TRemoteMessageSocketHandle = 0): Boolean;
    var
      rm: TRemoteMessage;
    begin
      rm.MessageType := rmtSystem;
      rm.System.SystemType := ASystemType;
      rm.System.SystemData := ASystemData;
      rm.System.SystemDataLen := ASystemDataLen;
      Result := RemoteMessage(rm, ATarget);
    end;
     
    //------------------------------------------------------------------------------
    class function Txxx.RemoteMessage(ARemoteMessage: TRemoteMessage; ATarget: TRemoteMessageSocketHandle = 0): Boolean;
    var
      MemoryStream: TMemoryStream;
    begin
      Result := False;
     
      try
        case ARemoteMessage.MessageType of
          rmtSystem:
            begin
              MemoryStream := TMemoryStream.Create();
              try
                MemoryStream.Write(ARemoteMessage.MessageType, SizeOf(ARemoteMessage.MessageType));
                MemoryStream.Write(ARemoteMessage.System.SystemType, SizeOf(ARemoteMessage.System.SystemType));
                MemoryStream.Write(ARemoteMessage.System.SystemDataLen, SizeOf(ARemoteMessage.System.SystemDataLen));
                if Assigned(ARemoteMessage.System.SystemData) and (ARemoteMessage.System.SystemDataLen > 0) then
                  MemoryStream.WriteBuffer(PByte(ARemoteMessage.System.SystemData)^, ARemoteMessage.System.SystemDataLen);
     
                // Envoi du Message immédiatement ou de façon asynchrone
                if FRemoteModuleMessenger.IsClient then
                  Result := InternalRemoteMessage(AsynchronousMode, rmdClientToServer, MemoryStream.Memory, MemoryStream.Size)
                else if FRemoteModuleMessenger.IsServer and (ATarget <> 0) then
                  Result := InternalRemoteMessage(AsynchronousMode, rmdServerToClient, MemoryStream.Memory, MemoryStream.Size, ATarget)
                else if FRemoteModuleMessenger.IsServer and (ATarget = 0) then
                  Result := InternalRemoteMessage(AsynchronousMode, rmdServerToAllClient, MemoryStream.Memory, MemoryStream.Size);
              finally
                MemoryStream.Free();
              end;
            end;
     
          rmtBusiness:
            begin
              // Envoi du Message immédiatement ou de façon asynchrone
              if FRemoteModuleMessenger.IsClient then
                Result := InternalRemoteMessage(AsynchronousMode, rmdClientToServer, @ARemoteMessage, SizeOf(ARemoteMessage));
            end;
     
          rmtBusinessResponse:
            begin
              MemoryStream := TMemoryStream.Create();
              try
                MemoryStream.Write(ARemoteMessage.MessageType, SizeOf(ARemoteMessage.MessageType));
                MemoryStream.Write(ARemoteMessage.BusinessResponse.BusinessRequest, SizeOf(ARemoteMessage.BusinessResponse.BusinessRequest));
                MemoryStream.Write(ARemoteMessage.BusinessResponse.BusinessResponseState, SizeOf(ARemoteMessage.BusinessResponse.BusinessResponseState));
                MemoryStream.Write(ARemoteMessage.BusinessResponse.BusinessResponseTreatStep, SizeOf(ARemoteMessage.BusinessResponse.BusinessResponseTreatStep));
                MemoryStream.Write(ARemoteMessage.BusinessResponse.BusinessResponseCode, SizeOf(ARemoteMessage.BusinessResponse.BusinessResponseCode));
                MemoryStream.Write(ARemoteMessage.BusinessResponse.BusinessResponseDataLen, SizeOf(ARemoteMessage.BusinessResponse.BusinessResponseDataLen));
                if Assigned(ARemoteMessage.BusinessResponse.BusinessResponseData) and (ARemoteMessage.BusinessResponse.BusinessResponseDataLen > 0) then
                  MemoryStream.WriteBuffer(PByte(ARemoteMessage.BusinessResponse.BusinessResponseData)^, ARemoteMessage.BusinessResponse.BusinessResponseDataLen);
     
                // Envoi du Message immédiatement ou de façon asynchrone
                if FRemoteModuleMessenger.IsServer then
                  Result := InternalRemoteMessage(AsynchronousMode, rmdServerToClient, MemoryStream.Memory, MemoryStream.Size, ATarget);
              finally
                MemoryStream.Free();
              end;
            end;
     
          rmtEvent:
            begin
              // Envoi du Message immédiatement ou de façon asynchrone
              if FRemoteModuleMessenger.IsServer then
                Result := InternalRemoteMessage(AsynchronousMode, rmdServerToAllClient, @ARemoteMessage, SizeOf(ARemoteMessage));
            end;
        end;
      except
        on E: Exception do
        begin
          OutputDebugString(PChar(Format('Txxx.RemoteMessage() - %s : %s', [E.ClassName(), E.Message])));
          Result := False;
        end;
      end;
    end;
     
    //------------------------------------------------------------------------------
    class function Txxx.InternalRemoteMessage(AAsynchronousMode: Boolean; ADestination: TRemoteMessageDestination; AData: Pointer; ADataLen: Integer; ATarget: TRemoteMessageSocketHandle = 0): Boolean;
    begin
      Result := False;
     
      if AAsynchronousMode and Assigned(FAsynchronousSender) then
      begin
        // Envoi du Message de façon asynchrone
        Result := FAsynchronousSender.AddRemoteMessage(ADestination, AData, ADataLen, ATarget);
      end
      else
      begin
        // Envoi du Message immédiatement
        FRemoteModuleMessengerLock.Acquire();
        try
          if ADestination = rmdClientToServer then
            Result := FRemoteModuleMessenger.SendDataToServer(AData, ADataLen)
          else if ADestination = rmdServerToClient then
            Result := FRemoteModuleMessenger.SendDataToClient(ATarget, AData, ADataLen)
          else if ADestination = rmdServerToAllClient then
            Result := FRemoteModuleMessenger.SendDataToAllClient(AData, ADataLen);
        finally
          FRemoteModuleMessengerLock.Release();
        end;
      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

  3. #3
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Avril 2011
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 51
    Points : 50
    Points
    50
    Par défaut
    Je te remercie pour toutes les explications que je vais essayer d'avaler
    Mais j'y arriverai !

    Petite question :
    si mes clients envoient une demande au serveur et que pour cette demande le serveur doit renvoyer une info bien précise, puis-je dire que si je n'ai aucun retour d'information avant la prochaine demande (toutes les 5s dans un Timer) mon serveur est coupé ou un cable est coupé ?

  4. #4
    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
    Citation Envoyé par franckjoane Voir le message
    Je te remercie pour toutes les explications que je vais essayer d'avaler
    Mais j'y arriverai !

    Petite question :
    si mes clients envoient une demande au serveur et que pour cette demande le serveur doit renvoyer une info bien précise, puis-je dire que si je n'ai aucun retour d'information avant la prochaine demande (toutes les 5s dans un Timer) mon serveur est coupé ou un cable est coupé ?
    en TCP le send() renvoie 0 pour indiquer une connexion coupée, le KEEP_ALIVE c'est pour avoir cette information même s'il n'y a pas de d'échange actif.

    en UDP il n'y a pas de connexion et donc pas d'accusé de réception, ce n'est qu'avec un délai de non-réponse à plusieurs sollicitations qu'on peut considérer que le serveur ne répond pas.

    mais le pire n'est pas le câble coupé, c'est le câble défectueux ! il va permettre par exemple la connexion mais pas l'échange de données, et là c'est la cata.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 454
    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 454
    Points : 24 866
    Points
    24 866
    Par défaut
    Citation Envoyé par franckjoane Voir le message
    puis-je dire que si je n'ai aucun retour d'information avant la prochaine demande (toutes les 5s dans un Timer) mon serveur est coupé ou un cable est coupé ?
    Si tu es en mode Bloquant sur le serveur, joue déjà avec "TWinSocketStream.WaitForData" et "Read", si WaitForData renvoie True et que Read renvoie 0 c'est une connexion rompue, et c'est en fermant côté serveur la socket que se produit le OnDisconnect
    Si tu es en mode non Bloquant sur le serveur, euh ... passe en mode bloquant pour le gérer via WaitForData !

    J'ai des souvenirs de Delphi 5, en mode non Bloquant, le OnDisconnect n'était top top pour une déconnexion sauvage

    Comme le mentionne Paul, quoi qu'il arrive à la prochaine Demande, tu auras une erreur car ton client ne pourra pas écrire dans la socket
    Et tout cas, c'est ainsi que je le gère


    Pour ma part, j'ai un TimeOut est de 3 minutes pour une demande bloquante et de 12 minutes pour une demande asynchrones

    A chaque demande, cela attribue un ID, ensuite le client gère un tableau des demandes en cours.
    Du côté serveur, c'est a peu près pareil en plus poussé car c'est le couple (Socket Handle, ID Demande) qui forme l'identifiant unique d'une demande ...

    Trois modules
    • un Client (il en existe plusieurs qui utilisent chacun des demandes différentes et ont une gestion de l'attente différente, certains bloquants, certains asynchrones)
    • un Serveur (service Windows) acceptant les demandes et en général produisant et déposant des fichiers CMD sur FTP et aspirant les fichiers ACK
    • un Logiciel d'un tiers aspirant les fichiers CMD du FTP et déposant les fichiers ACK


    le Client fait une demande de traitement au Serveur, cela passe par plusieurs états :
    • Demande prise en compte
    • Demande en cours de traitement
    • Demande traitée et fichier généré
    • Ajout du fichier généré dans la file d'attente FTP
    • Envoi Fichier FTP
    • Confirmation Envoi FTP
    • Demande accepté par Logiciel Tiers (réception du ACK)


    A Chaque étape, le serveur notifie son client de l'étape franchie (et de son succès ou de son échec)
    Parfois, le client peut faire 1000 demandes d'un coup en quelques secondes, c'est du coup 1000 fichiers déposés le FTP, le logiciel tiers prenant 1 à 2 secondes pour chaque fichier, c'est comme cela que le délai entre la demande initiale et l'acceptation finale peut prendre 12 minutes
    Pour l'utilisateur, c'est transparent, il a une liste avec des couleurs, et des compteurs affichant le nombre "En Attente", "Validé", "Refusé"


    D'ailleurs, ce n'est pas le seul motif ou le serveur ne répond pas, cela peut être un plantage interne, genre un thread en dead lock
    la partie TCP fonctionne mais la partie métier elle est plantée
    Et c'est le problème que j'ai eu une fois, je n'ai pas pu vraiment le comprendre, je ne sais pas si c'est un SQL qui s'est bloqué (ça nous arrive) ou alors un Dead Lock de MREWS
    Dans le doute, le serveur ne fait pas un SendStream directement, il passe par une file d'attente et c'est un autre thread qui envoie la notification
    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

  6. #6
    Membre du Club
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Avril 2011
    Messages
    51
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2011
    Messages : 51
    Points : 50
    Points
    50
    Par défaut
    Bon je vais passer en mode bloquant et suivre tes précieuses indications !

    Je marque résolu. Et j'étudie le mode bloquant !

    Merci.

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

Discussions similaires

  1. Détection de cellules coupe de microscope
    Par Marie27 dans le forum Traitement d'images
    Réponses: 4
    Dernier message: 11/04/2014, 17h10
  2. TServerSocket: Détection déconnexion client
    Par Neo41 dans le forum C++Builder
    Réponses: 3
    Dernier message: 04/09/2004, 19h46
  3. Réponses: 2
    Dernier message: 05/12/2002, 16h55
  4. Détections avec WebBrowser
    Par Wazo_Sportive dans le forum Composants VCL
    Réponses: 4
    Dernier message: 11/08/2002, 19h32
  5. Détection de 2 touches appuyées
    Par cyrose dans le forum C++Builder
    Réponses: 2
    Dernier message: 26/07/2002, 16h25

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