AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Indy TCPServer beenden mit toten Clients
Thema durchsuchen
Ansicht
Themen-Optionen

Indy TCPServer beenden mit toten Clients

Ein Thema von hsg · begonnen am 8. Jun 2012 · letzter Beitrag vom 14. Jun 2012
Antwort Antwort
Seite 1 von 3  1 23      
hsg

Registriert seit: 24. Apr 2006
Ort: Wustermark
354 Beiträge
 
Delphi 10.3 Rio
 
#1

Indy TCPServer beenden mit toten Clients

  Alt 8. Jun 2012, 12:16
Hallo zusammen,

ich kämpfe gerade mit einem TIdTCPServer(Indy10), der sich mit unseren PDAs übers WLan unterhält. Leider kommt es vor, dass der Mitarbeiter mit seinem PDA den Bereich des WLan verlässt oder der PDA aus anderen Gründen die Verbindung zum Netzwerk verliert.

Kommt der PDA wieder ins Netz, meldet er sich beim Server auf einem neuen Port an und gut ist. Im Server ist der PDA zweimal aufgelistet, macht aber keine Probleme. Wird der Server nun beendet, bekommen beide Client-Verbindungen die Abmeldung und der Server lässt sich dann sauber beenden.

Anders ist es allerdings, wenn der PDA beim Beenden des Servers nicht mehr erreichbar ist. Dann versucht der Server die Verbindung zu beenden, bleibt dabei aber hängen.

Beim Server ist die TerminateWaitTime gesetzt,
in den jeweiligen Connections die ConnectTimeout und die ReadTimeout.

Leider bekomme ich kein Disconnect vom Client, auch keine Exception im Server.

Was kann ich tun, damit der Server sauber beendet werden kann?

Gruß
Jörg

Umgebung: Server mit Indy10.1 in BDS 2006 geschrieben.
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#2

AW: Indy TCPServer beenden mit toten Clients

  Alt 8. Jun 2012, 13:33
Zitat:
Umgebung: Server mit Indy10.1 in BDS 2006 geschrieben.
Wie versucht der Server denn die Verbindung zu beenden - soll da noch etwas über den IOHandler (Socket) an den Client gesendet werden, und ist dabei ein Timeout angegeben?

p.s. das ist eine sehr alte Version, spricht etwas dagegen die aktuelle Version 10.5.8.(4768) zu testen?
Michael Justin
habarisoft.com
  Mit Zitat antworten Zitat
hsg

Registriert seit: 24. Apr 2006
Ort: Wustermark
354 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: Indy TCPServer beenden mit toten Clients

  Alt 8. Jun 2012, 13:53

Wie versucht der Server denn die Verbindung zu beenden - soll da noch etwas über den IOHandler (Socket) an den Client gesendet werden, und ist dabei ein Timeout angegeben?
Der Server versucht etwas zu senden (IOHandler.Writeln('CLOSE_REQUEST@ ') Über diesen Punkt kommt er aber ohne Probleme hinweg.
Wie gebe ich ein TimeOut beim Schreiben an?
Hängen scheint er beim beenden des Threads.

Was mich irritiert ist die Tatsache, dass der tote Socket beim erreichen des Netzes ja erfolgreich geschlossen wird (wenn also zwei Socketverbindungen vorhanden sind und die zweite noch lebt. Nur wenn das Gerät überhaupt nicht mehr ansprechbar ist, begeht der Server Suizid.


p.s. das ist eine sehr alte Version, spricht etwas dagegen die aktuelle Version 10.5.8.(4768) zu testen?
Werde ich Montag mal ausprobieren.

Gruß Jörg
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#4

AW: Indy TCPServer beenden mit toten Clients

  Alt 8. Jun 2012, 14:05
Der Server versucht etwas zu senden (IOHandler.Writeln('CLOSE_REQUEST@ ') Über diesen Punkt kommt er aber ohne Probleme hinweg.
Ok, das Senden an den Socket funktioniert - das ist normal, auch wenn die Gegenseite nicht zuhört.

und das:

Zitat:
Anders ist es allerdings, wenn der PDA beim Beenden des Servers nicht mehr erreichbar ist. Dann versucht der Server die Verbindung zu beenden, bleibt dabei aber hängen.
verstehe ich als ob nach dem obigen "Writeln" noch etwas vom Server gemacht wird, zum Beispiel auf die Antwort des Clients auf das 'CLOSE_REQUEST@' zu warten. Und das kann natürlich nicht mehr erfolgreich sein wenn der Client nicht da ist. In diesem Fall sollte der Server die dann auftretende Exception (vermutlich ReadTimeOut) eventuell nicht mehr behandeln und Indy automatisch den Thread beenden lassen, wenn ich mich richtig erinnere.

Beim IOHandler.Read kann ein TimeOut direkt als Parameter angegeben werden. Der Default ist relativ lange, was wie ein Hänger aussehen kann.

(Send-Timeouts sind plattformspezifisch, nicht als Parameter oder Properties, konfigurierbar und hier anscheinend nicht das Problem)

Hope this helps,
Michael Justin

Geändert von mjustin ( 8. Jun 2012 um 14:15 Uhr)
  Mit Zitat antworten Zitat
hsg

Registriert seit: 24. Apr 2006
Ort: Wustermark
354 Beiträge
 
Delphi 10.3 Rio
 
#5

AW: Indy TCPServer beenden mit toten Clients

  Alt 8. Jun 2012, 14:19
Zitat:
Anders ist es allerdings, wenn der PDA beim Beenden des Servers nicht mehr erreichbar ist. Dann versucht der Server die Verbindung zu beenden, bleibt dabei aber hängen.
klingen als ob nach dem obigen "Writeln" noch etwas vom Server gemacht wird, zum Beispiel auf die Antwort des Clients auf das 'CLOSE_REQUEST@' zu warten. Und das kann natürlich nicht mehr erfolgreich sein wenn der Client nicht da ist. In diesem Fall sollte der Server die dann auftretende Exception (vermutlich ReadTimeOut) eventuell nicht mehr behandeln und Indy automatisch den Thread beenden lassen, wenn ich mich richtig erinnere.
Der ReadTimeOut ist gesetzt (300 sek. habe aber den Server eine viertel Stunde in Ruhe gelassen, er hing immer noch
Die Clients schließen auf die Aufforderung nur die Sockets. Es wird nichts gesendet.
Exception wird ja auch keine geworfen. Zu keinem Zeitpunkt.

Beim IOHandler.Read kann ein TimeOut direkt als Parameter angegeben werden. Der Default ist relativ lange, was wie ein Hänger aussehen kann.

(Send-Timeouts sind plattformspezifisch, nicht als Parameter oder Properties, konfigurierbar und hier anscheinend nicht das Problem)

Hope this helps,
Einzig allein in der OnExecute-Routine wird der Inputbuffer ausgelesen

Delphi-Quellcode:
  if AContext.Connection.IOHandler.InputBufferIsEmpty then
     begin
       SleepEx(10, True);
       Exit;
     end;

  oAnswer := TStringList.Create();

  try
    bTest := True;
    cMess := Trim(AContext.Connection.IOHandler.InputBufferAsString());
    //cMess := Trim(AContext.Connection.IOHandler.ReadLn());

    if cMess = 'then
       begin
         Exit;
       end;
...
es wird also explizit vorher nachgesehen, ob etwas im Puffer steht. Auch kommt er beim Beenden nicht an diese Stelle. Kann somit leider ausgeschlossen werden
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#6

AW: Indy TCPServer beenden mit toten Clients

  Alt 8. Jun 2012, 15:26

Exception wird ja auch keine geworfen. Zu keinem Zeitpunkt.
Werden Exceptions eventuell so behandelt, dass Indy sie nicht bemerkt? Indy verwendet einige (selbstdefinierte) Exceptions wie EIdConnClosedGracefully zur Steuerung:

Zitat:
You need to get rid of your exception handling, or at least re-raise any EIdException-derived exceptions you catch. You are blocking Indy's internal notifications from being dispatched and processed correctly.
(https://forums.embarcadero.com/messa...ssageID=257582)
Michael Justin
  Mit Zitat antworten Zitat
Benutzerbild von sx2008
sx2008

Registriert seit: 16. Feb 2008
Ort: Baden-Württemberg
2.332 Beiträge
 
Delphi 2007 Professional
 
#7

AW: Indy TCPServer beenden mit toten Clients

  Alt 10. Jun 2012, 04:26
Wenn eine TCP-Verbindung physisch getrennt wird, kann das keiner der beteiligten Partner erkennen ohne dass Daten gesendet werden.
Nur wer Daten sendet, kann erkennen dass die Verbindung unterbrochen ist.
Dazu gibt es in vielen Protokollen einen NOP-Befehl (NO-Operation, Befehl der nichts tut).
Man kann aber auch ein Datenpaket der Länge 0 senden, wobei das aber nicht so zuverlässig wie ein NOP-Befehl ist.
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#8

AW: Indy TCPServer beenden mit toten Clients

  Alt 10. Jun 2012, 08:10
Wenn eine TCP-Verbindung physisch getrennt wird, kann das keiner der beteiligten Partner erkennen ohne dass Daten gesendet werden.
Die Verbindung wird, wenn ich es soweit richtig verstanden habe, serverseitig zuerst logisch beendet durch senden (IOHandler.Writeln('CLOSE_REQUEST@ '), und bei dieser Operation hängt Indy noch nicht. Indy beendet den Server aber danach nicht, so dass die Anwendung nicht terminiert.
Michael Justin
habarisoft.com
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#9

AW: Indy TCPServer beenden mit toten Clients

  Alt 10. Jun 2012, 08:11


Der Server versucht etwas zu senden (IOHandler.Writeln('CLOSE_REQUEST@ ') Über diesen Punkt kommt er aber ohne Probleme hinweg.
Folgt nach dem

Delphi-Quellcode:

IOHandler.Writeln('CLOSE_REQUEST@ ')
noch ein sauberes Beenden der Verbindung? (Schliessen des Sockets)

Delphi-Quellcode:

AContext.Connection.Disconnect

Wenn das Protokoll geändert werden kann, wäre ein Heartbeat-Verfahren eventuell eine Verbesserung, damit der Server verloren gegangene Verbindungen schneller erkennt und abräumt.

Update:

unter http://www.delphipraxis.net/157267-i...er-thread.html

werden noch diese Zeilen regelmäßig im Server OnExecute ausgeführt:
Delphi-Quellcode:
    AContext.Connection.IOHandler.CheckForDisconnect(False, True);
    AContext.Connection.CheckForGracefulDisconnect(False);
Michael Justin
habarisoft.com

Geändert von mjustin (10. Jun 2012 um 08:54 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#10

AW: Indy TCPServer beenden mit toten Clients

  Alt 10. Jun 2012, 13:23
Ich hatte soeiein Problem beim DataSnap bemerkt, welches intern auch Indy-TCP nutzt (versteckt hinter den benutzen DBConnections).

Wenn die Connection z.B. durch ein Netzwerkproblem getrennt wurde oder teilweise auch wenn Clientanwendungen abgestürzt sind, dann wurden die Connections nicht odnungsgemäß getrennt.
Der Server denkt dann die Clients seien noch vorhanden und beim Runterfahren sendet er dann allen "bekannten" Clients eine "ich bin dann mal Weg"-Nachricht, damit sie ihrerseits die Verbindung ordentlich trennen können. (ja, auch Clients können eventuell hängen, wenn der Server weg ist)

Wobei er dann einfach hängen bleibt, wenn er auf soeinen toten Client trifft.


Leider läßt sich dagegen nichts machen. (wir haben alles Mögliche versucht)




Zum Teil ist das auch ein Problem von Windows, denn dieses schließt die Ports nicht, wenn die Connection abreißt, womit Indy (im Server oder auch im Client) nicht darüber informiert wird, daß die Connection eigentlich weg ist.

Standardmäßg sendet Windows keine NOPs (oder sowas), über die "aktiven" Ports. Es gibt zwar soeine Funktion, welche aber eigentlich nie aktiv ist, oder die Zeit war nur ewig hoch eingestellt. (nicht ganz sicher ... müßte nochmal nachsehn)
Es testet also selbstständig keine Portverbindungen, womit es Windows oftmals erst nach 24 Stunden auffällt und so lange die Verbindung angeblich noch besteht.
$2B or not $2B
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


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 01:48 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