AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Indy TCP-Anwendung: Wie eine tote Verbindung loswerden?
Thema durchsuchen
Ansicht
Themen-Optionen

Indy TCP-Anwendung: Wie eine tote Verbindung loswerden?

Ein Thema von FoxOne · begonnen am 24. Mai 2007 · letzter Beitrag vom 25. Mai 2007
Antwort Antwort
FoxOne

Registriert seit: 24. Mai 2007
Ort: Wien
7 Beiträge
 
#1

Indy TCP-Anwendung: Wie eine tote Verbindung loswerden?

  Alt 24. Mai 2007, 16:59
Hallo!

Da ich mit fehlender Kenntnis übergreifender Zusammenhänge der Indy-TCP Funktionalität zu kämpfen habe, bitte ich in folgener Sache um Hilfe:

Mit meiner Indy9 TCPServer/Client-Anwendung habe ich ein Problem mit Client-seitig unterbrochenen Verbindungen. Wenn ein Client sich für bestimmte Zeit nicht rührt bzw. keine Daten erhält, kann ich davon ausgehen, dass die Verbingung unterbrochen wurde (z.B. WLAN-Ausfall). In diesem Fall hängt der neuerliche Verbindungsaufbau zum Server. Der Server muss neu gestartet werden, dass die Anwendung wieder läuft.
Das passiert bei langsamer Verbindung (GPRS) immer, bei schneller (XDSL) selten.

Mein Ansatz war, den zugehörigen idPeerThread von 'Hand' zu terminieren, weil ich diesem im Verdacht habe, in einem Deadlock zu hängen. Leider nutzt das nichts (Code siehe unten).

Hat jemand eine Idee, wie ich den Server wieder frei bekomme bzw. die 'Altlasten' der toten Verbindung loswerte?

Vielen Dank!




Delphi-Quellcode:

//--- dip : IP-Adresse der Verbindung, deren Thread terminiert werden soll


function TBaseTCPServer.TerminateConnection(dip: string): boolean;
var i : integer;
    List : TList;
begin

  result:=true;
  if not idTCPServer.Active then Exit;

  List := idTCPServer.Threads.LockList;
  

  i:=List.count-1;
  while (i>=0) and
      (AnsiCompareStr(TidPeerThread(List.Items[i]).Connection.Socket.Binding.PeerIP,dip)<>0) do
    dec(i);

  if i>=0 then
  begin
    try
      //--- Sicherheitshalber disconnecte ich alles, was mit dem Thread in Zusammmenhang steht
      TidPeerThread(List.Items[i]).Connection.Disconnect;
      TidPeerThread(List.Items[i]).Connection.DisconnectSocket;
    finally
        TidPeerThread;(List.Items[i]).Terminate;
    end;
  end;

  idTCPServer.Threads.UnlockList;
  list.Clear;
  
end;
  Mit Zitat antworten Zitat
supermuckl

Registriert seit: 1. Feb 2003
1.340 Beiträge
 
FreePascal / Lazarus
 
#2

Re: Indy TCP-Anwendung: Wie eine tote Verbindung loswerden?

  Alt 24. Mai 2007, 17:50
ähm im server kannst du doch mit timeouts arbeiten ?!
dann gibts auch keine deadlocks sondern nur kleine verzögerungen durch die ablaufenden timeouts

es geht ja sowieso alles für jeden client in einem eigenen thread ab (OnExecute)


hab da schon einige client serveranwendungen gebaut und nie probs gehabt

beispielsweise im OnServerExecute kannst du die ReadLn's mit Timeouts versehen:

athread.Connection.ReadLn(#$A,1000); <- Timeout von 1sec

du kannst auch hergehen und die clients dauerhaft pakete an den server schicken lassen
und wenn die nimmer ankommen kann der server die automatisch alle killen (die client thread leichen)

hab dir mal nen altes projekt mit indy9 angehängt, das diese pingerei usw verdeutlichen soll
allerdings ohne killen
Angehängte Dateien
Dateityp: zip tcp-timeout-test_114.zip (674,7 KB, 11x aufgerufen)
Das echte Leben ist was für Leute...
... die im Internet keine Freunde finden!
  Mit Zitat antworten Zitat
FoxOne

Registriert seit: 24. Mai 2007
Ort: Wien
7 Beiträge
 
#3

Re: Indy TCP-Anwendung: Wie eine tote Verbindung loswerden?

  Alt 24. Mai 2007, 18:37
Vielen Dank für die Antwort und die Files!

Nun ist es so, dass ich eigentlich eh dasselbe bei meinem Projekt mache:
Der Client fragt in regelmäßigen Zeitabständen um Daten an, wenn diese Zeit überschritten wird, weiß der Server, dass der Client verblichen ist. Dann wir die oben gepostete Routine 'TerminateConnection' aufgerufen, die den Server aber leider im Deadlock (?) verbleiben läßt.
Den Deadlock kann ich leider nicht so einfach durch ein Zeitlimit ausschließen, weil ich (unter anderem) ReadStream verwende, das anders als Readln keinen Parameter dafür hat.

Ich habe übrigens auch nur Disconnect und DisconnectSocket probiert, das führt aber zum selben Effekt: Man kann sich nicht mehr mit dem Server verbinden. Im Detail: es wird ein neuer Thread erstellt, aber in die OnReceive-Prozedur gelangt man nicht. Auch gar nichts tun bringt nichts, dann wird laufend die Exception 'Socket Error # 10054: connection reset by peer' in OnReceive geworfen (obwohl der Client gar nichts mehr über die unterbrochene Verbindung schicken kann??).


Kurz nach Beenden der Server-Anwendung kommt übrigens die Meldung 'Terminate Thread Timeout'.

Den ganzen Tag hab ich mir schon damit um die Ohren geschlagen, ich bin wirklich für jeden Hinweis dankbar!

Viele Grüße,
Martin
  Mit Zitat antworten Zitat
supermuckl

Registriert seit: 1. Feb 2003
1.340 Beiträge
 
FreePascal / Lazarus
 
#4

Re: Indy TCP-Anwendung: Wie eine tote Verbindung loswerden?

  Alt 24. Mai 2007, 20:07
ich vermute mal, das dein deadlock, der im clientthread hängt, auch den thread.terminate abhält zu wirken.
somit sind auch dann die threads noch alle da und können nicht beendet werden, wenn dein prog abgeschossen wird.

eine lösung für blockierte threads abschiessen hab ich aber net (evtl von aussen irgendwie killen mit ner api über die threadid? ka)
Das echte Leben ist was für Leute...
... die im Internet keine Freunde finden!
  Mit Zitat antworten Zitat
Udontknow

Registriert seit: 17. Jun 2002
223 Beiträge
 
#5

Re: Indy TCP-Anwendung: Wie eine tote Verbindung loswerden?

  Alt 25. Mai 2007, 13:40
Hallo!

Ich würde die Threadhandhabung der Serverkomponente überlassen.
Sollte es nicht reichen, innerhalb der OnExecute-Routine einfach das Disconnect aufzurufen? Der Verbindungsthread wird doch dann von alleine beendigt. Vielleicht noch ein Abort dazu, damit du die (Sub-)Routinen garantiert alle verlässt, und fertig...

Cu,
Udontknow
  Mit Zitat antworten Zitat
FoxOne

Registriert seit: 24. Mai 2007
Ort: Wien
7 Beiträge
 
#6

Re: Indy TCP-Anwendung: Wie eine tote Verbindung loswerden?

  Alt 25. Mai 2007, 16:52
Vielen Dank für die Antwort!

Habe inzwischen weiter herumprobiert und kann bestätigen, dass der Socket den Thread ordentlich wegputzt, wenn eine bestimmte Zeit verstrichten ist (irgendein Timeout von ca. 30s, ich weiß nicht, wie bzw. wo der zu setzen ist). Es wird dann die bereits erwähnte Exception 'Connection reset by peer' geworfen.
Bei meinen Internetrecherchen bin ich auf den Tip gestoßen, diese Exception nocheinmal anzustoßen, weil sie Indy intern noch verwertet, also:
Delphi-Quellcode:

uses ....,IdException;

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
begin

  try

  //--- Server Arbeit hier
  //..
  //..

  except
    on e: EIdSocketError do
    begin //-- Indy exception
        ErrorOut('Socket Exception in OnExecute: ' + e.message);
        Raise; //--- wichtig!
    end;

    on e: exception do
    begin //-- andere exception
        ErrorOut('Exception in MyOnReceive: ' + e.message);
        Raise; //--- wichtig?

    end;
  end;

end;

Dies hat soweit geholfen, dass die Exception nun nur mehr einmal kommt. Wenn ich mir vor dem Timeout und danach die Threadliste anschaue, dann ist nachher der 'tote' Thread tatsächlich weg.
Beim erneuten starten des Clients wird dann die Verbindung soweit aufgebaut, dass ein neuer TidPeerThread in der Threadliste ist, aber leider wird nun die OnExecute-Prozedur des Servers nicht mehr aufgerufen. Somit hängt Client-Server-Verbindung, aber eben nur in etwa 50% der Fälle bei langsamer Verbindung. Der Rest der Server-Applikation (Datenerfassung etc.) läuft ungestört weiter. Beim Beenden des Servers kommt dann wenig überraschen die Exception 'Terminate Thread Timeout'.

Habe inzwischen auch einen OnListenException-Handler implementiert, der springt aber nicht an.

Ich bin also weiterhin ratlos. Wie kann ich den Server wieder freibekommen?
  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 11:14 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