AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Indy TCPClient Connection Status
Thema durchsuchen
Ansicht
Themen-Optionen

Indy TCPClient Connection Status

Ein Thema von Delphi-Narr · begonnen am 19. Mär 2015 · letzter Beitrag vom 25. Mär 2015
Antwort Antwort
Benutzerbild von Delphi-Narr
Delphi-Narr

Registriert seit: 29. Aug 2009
Ort: Duisburg
437 Beiträge
 
Delphi 2007 Professional
 
#1

AW: Indy TCPClient Connection Status

  Alt 20. Mär 2015, 11:01
Ja das werde ich wohl tun
Heartbeats werden auch verschickt, nur nicht so oft. Das werde ich dann mal anpassen.
Komisch, dass das bei Windows-"interner" Kommunikation die Abfrage das richtige Resultat lieferte.
  Mit Zitat antworten Zitat
Benutzerbild von Delphi-Narr
Delphi-Narr

Registriert seit: 29. Aug 2009
Ort: Duisburg
437 Beiträge
 
Delphi 2007 Professional
 
#2

AW: Indy TCPClient Connection Status

  Alt 24. Mär 2015, 10:55
Habe hierzu nochmal eine Frage:
Ich habe jetzt den Heartbeat eingebaut, der Client schickt in einem Intervall die Heartbeats und der Server antwortet.
In der ContextClass des Servers werden die MacAdresse und der Zeitpunkt des letzten Heartbeats des Clients gespeichert. In festen Intervallen räumt der Server dann auf, d.h. er durchläuft die Liste der verbundenen Clients und alle, die zu lange keinen Heartbeat mehr hatten, werden disconnected - zumindest in der Theorie.
Der Client erkennt inzwischen korrekt, ob er keine Verbindung mehr hat, der Server vom Prinzip her auch.

Delphi-Quellcode:
procedure TMyServer.HeartbeatCheck();
var
    ContextList:TList;
    Context:TIdContext;
    i:integer;
begin
    ContextList := TCPServer.Contexts.LockList;
    try
       for i := 0 to ContextList.Count-1 do
           begin
                Context := TIdContext(ContextList.Items[i]);
                if (IncSecond(TClientIdentifier(Context).Heartbeat, CLIENTTIMEOUT) < Now) and (TClientIdentifier(Context).Heartbeat <> 0) then
                   begin
                        Log('Client '+TClientIdentifier(Context).Mac+' timed out', ltE);
                        TIdContext(ContextList.items[i]).Connection.IOHandler.close;
                        TIdContext(ContextList.items[i]).Connection.Disconnect();
                   end;
           end;
     finally
        TCPServer.Contexts.UnlockList;
     end;
end;
Wenn ein Client die Verbindung verliert, wird das entsprechend geloggt, doch in JEDEM Durchlauf wird er erneut als timed out erkannt - dabei sollte er ja eigentlich aus der Liste gelöscht werden?!
Und auch wenn der Client die Verbindung wieder aufnimmt und Heartbeats schickt, wird er dennoch wieder getrennt.
Im OnDisconnect des Servers wird eigentlich ebenfalls geloggt, dass ein bestimmter Client die Verbindung getrennt hat - dies wird in der Heartbeat Methode aber offenbar gar nicht ausgelöst. Vielleicht ist es ja nur ein ganz einfacher blöder Fehler

Viele Grüße!
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.005 Beiträge
 
Delphi 2009 Professional
 
#3

AW: Indy TCPClient Connection Status

  Alt 24. Mär 2015, 15:25
In festen Intervallen räumt der Server dann auf, d.h. er durchläuft die Liste der verbundenen Clients und alle, die zu lange keinen Heartbeat mehr hatten, werden disconnected - zumindest in der Theorie.
Auf Anhieb kann ich keinen Fehler erkennen. Frage: funktioniert es unter Windows, aber unter Linux nicht? Oder auf beiden System nicht?

Als Alternative würde ich noch erwägen die Heartbeat-Prüfung nicht als Schleife über alle Context Objekte zu realisieren sondern innerhalb der OnExecute - Loop. Damit spart man sich das LockList, da man in OnExecute den zu prüfenden Context threadsicher untersuchen kann. (Auf diese Idee hat mich ein Beitrag von Remy Lebeau gebracht: http://stackoverflow.com/a/1534800/80901).

In der OnExecute Loop kann man dann einfach eine (Indy-) Exception auslösen wenn der aktuelle Kontext zu lange kein Heartbeat-Signal mehr vom Client sah.

Ausgehend von diesem Codeschnipsel (http://stackoverflow.com/a/14180366/80901):

Delphi-Quellcode:
procedure TMainForm.IdTCPServerExecute(AContext: TIdContext);
var
  ...
begin
  ...

  if AContext.Connection.IOHandler.InputBufferIsEmpty then
  begin
    if not AContext.Connection.IOHandler.CheckForDataOnSource(100) then
    begin
      AContext.Connection.IOHandler.CheckForDisconnect;
      Exit;
    end;
  end;

  TCliContext(AContext).ProccessMsg;
  TCliContext(AContext).Activity_time := Now();
end;
... würde man nach dem CheckForDataOnSource auch die Activity_time prüfen und - falls sie "zu alt" ist - eine TIdException auslösen anstatt die Methode mit Exit zu verlassen. Durch die Exception erfährt der Server, dass er den Context freigeben und die Verbindung trennen soll.
Michael Justin
  Mit Zitat antworten Zitat
Benutzerbild von Delphi-Narr
Delphi-Narr

Registriert seit: 29. Aug 2009
Ort: Duisburg
437 Beiträge
 
Delphi 2007 Professional
 
#4

AW: Indy TCPClient Connection Status

  Alt 24. Mär 2015, 15:38
Unter Windows habe ich das nicht getestet, unter Linux scheint der Eintrag auf jeden Fall nicht korrekt gelöscht werden.
Das OnExecute wird doch nur ausgeführt, wenn was vom Client kommt oder nicht? Wenn also kein Client mehr irgendetwas auslöst - weil die Verbindung getrennt wurde - kann der disconnect dann überhaupt erkannt werden?
Das Problem ist ja nicht, den Context zu untersuchen, sondern den zugehörigen Client zu löschen.
Ich werde die Lösung auf jeden Fall mal testen
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.005 Beiträge
 
Delphi 2009 Professional
 
#5

AW: Indy TCPClient Connection Status

  Alt 24. Mär 2015, 15:50
Das OnExecute wird doch nur ausgeführt, wenn was vom Client kommt oder nicht?
OnExecute wird vom Server in einer Schleife immer wieder ausgeführt. Es gibt ja auch Fälle in denen der Client nur einmal eine Verbindung herstellt und dann wartet, bis der Server Daten sendet, und dann weiter wartet.

Der Server würde dann in OnExecute prüfen, ob er eine neue Nachricht für den Client hat, und falls nein, die Methode verlassen ... die dann aber "sofort" wieder aufgerufen wird. (Das kann zu einer 100 % Auslastung der CPU führen, dann muss noch eine Bremse wie Sleep eingebaut werden).

Das saubere clientseitige Disconnect würde der Server beim Read oder Write, oder mit CheckForDataOnSource / CheckForDisconnect feststellen.
Michael Justin
  Mit Zitat antworten Zitat
Benutzerbild von Delphi-Narr
Delphi-Narr

Registriert seit: 29. Aug 2009
Ort: Duisburg
437 Beiträge
 
Delphi 2007 Professional
 
#6

AW: Indy TCPClient Connection Status

  Alt 25. Mär 2015, 14:18
So, mit ein paar Anpassungen hat es dann funktioniert. Der disconnect wird in der OnExecute korrekt durchgeführt. Nur der Client kriegt es jetzt nicht immer mit
Aber in den meisten Fällen schon.

Leider funktioniert auch CheckForDisconnect nicht korrekt. Läuft zwischen Windows und Linux mit dem Setup wohl nur manuell...

Danke auf jeden Fall für die Hilfe!
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:06 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz