TCP-Client: Abfrage nach Verbindungsabbruch zum TCP-Server

  • Ich habe auf einem Linux-Rechner ein von mir in C++ geschriebenes Programm in einen TCP-Server eingebettet. Die Kommunikation zwischen dem Autoit-Client und dem Linux-Server funktioniert grundsätzlich reibungslos und fehlerfrei via TCP.


    Ich will für den Fehlerfall der unterbrochenen TCP-Verbindung (z.B. auch unvorhergesehenes Schliessen des Linux-TCP-Servers) beim Autoit-Client das entsprechende Signal einbauen. Andersherum funktioniert das problemlos (abruptes Schliessen des Autoit-Clients).


    Mit TCPConnect-Abfrage bekomme ich das nicht hin. Vermutlich weil hier das Socket abgefragt wird, das Autoit aufbaut und das erst mit TCPShutdown geschlossen wird. Egal was auf der anderen Seite passiert. Eine Abfrage funktioniert nur zuverlässig beim Start und Aufbau der Verbindung.


    Hat jemand eine hilfreiche Idee?

  • Mit TCPConnect-Abfrage bekomme ich das nicht hin. Vermutlich weil hier das Socket abgefragt wird, das Autoit aufbaut und das erst mit TCPShutdown geschlossen wird. Egal was auf der anderen Seite passiert. Eine Abfrage funktioniert nur zuverlässig beim Start und Aufbau der Verbindung.

    Du willst also den Fall simulieren wo der Server abgestürzt ist und der Client Anfragen sendet?

    Wenn deine Verbindung nach dem TCPConnect abgestürzt ist (also die Verbindung etabliert werden konnte) kannst du einfach Heartbeats senden, kleine definierte Pakete auf die der Server antworten muss oder auch nicht.

    Wenn du beim TCPSend ein @error bekommst ist das Senden fehlgeschlagen und die Verbindung ist vermutlich zusammengebrochen.

  • Du willst also den Fall simulieren wo der Server abgestürzt ist und der Client Anfragen sendet?


    Muss nicht abgestürzt sein. Ich steuere hier eine sensible Datenleitung, die nicht unkontrolliert abbrechen darf. Kann also auch ein (W)LAN-Ausfall sein ...

    Wenn deine Verbindung nach dem TCPConnect abgestürzt ist (also die Verbindung etabliert werden konnte) kannst du einfach Heartbeats senden, kleine definierte Pakete auf die der Server antworten muss oder auch nicht.


    Ich will keine dauerhaften Lasten generieren. Auf der anderen Seite läuft eine Echtzeit-Anwendung. Ideal wäre es, das nicht mehr korrekt vorhandene Socket in einer Schleife zu bemerken.


    Wenn du beim TCPSend ein @error bekommst ist das Senden fehlgeschlagen und die Verbindung ist vermutlich zusammengebrochen.

    Das wäre aber Zufall, wenn gerade ein Kommando vom Client gesendet wird. D.h. es wäre viel zu spät, die nicht mehr vorhandene Verbindung im Zuge eines Kommandos festzustellen.

  • Ich habe jetzt nochmal was getestet. Meiner Meinung nach funktioniert da grundsätzlich etwas nicht in Autoit-TCP ... oder ich verstehe es nicht :/


    Hier mal eine kleine Modifikation anhand der Hilfe-Funktionsscripten. Leicht angepasst. Am besten zuerst den Server kompilieren und starten, danach den Client. Ohne den eingefügte Bereich (Client sendet $recv ...) beendet der Client, weil $iSocket <> -1


    1.) Client sendet an Server: $recv


    2.) Server empfängt das und reagiert auf diese Nachricht (Schleife!) in der Folge mit @error: $iSocket <> -1


    SERVER:

  • Hier mal eine kleine Modifikation anhand der Hilfe-Funktionsscripten. Leicht angepasst. Am besten zuerst den Server kompilieren und starten, danach den Client. Ohne den eingefügte Bereich (Client sendet $recv ...) beendet der Client, weil $iSocket <> -1

    Deine Struktur sieht auch ziemlich sketchy aus.

    Du solltest grundsätzlich in der Schleife wo du Clients annimmst nicht auf Nachrichten horchen, denn beim nächsten Durchlauf wird die Clientvariable mit TCPAccept -1 überschrieben, da sich dein Client ja nur einmal verbindet.

    Dass dein Client nicht mehr den Server erreichen kann liegt wohl daran, dass AutoIt erkennt, dass du die Socketvariable überschrieben hast und automatisch die Verbindung beendet.


    Warte im Server bis du einen Client hast und springe aus der Schleife raus, dann gehst du in eine Schleife rein, in der du eingehende Daten auswertest und ggf. antwortest.

    Dein macht es ja einigermaßen richtig, einmal verbinden und danach in einer Schleife Senden/Empfangen.

  • War ein nicht optimal gewähltes Beispiel, weil es mein Problem nicht wirklich nachstellt. Muss dazu sagen, dass mein 2.) oben nicht passt. Das müßte an der Stelle so sein, dass man via Taskmanager den Server killt. Hier allerdings gibt TCPRecv den richtigen @error aus: Werde versuchen, mein Problem weiter einzukreisen...

  • Wann immer ich in AutoIt mit TCP-Verbindungen hantiere, nutze ich Kips TCP-UDF. Diese basiert auf Events, d.h. du registrierst eine Funktion für ein Ereignis (bspw. Datenempfang), die dann von der UDF aufgerufen wird. Das finde ich wesentlich angenehmer zu programmieren. Dort gibt es auch die Möglichkeit, ein Verbindungsabbruch-Ereignis zu registrieren. Ich weiß nicht, wie Kip das intern umgesetzt hat, aber wenn du die Info in AutoIt irgendwie bekommen kannst, dann wird diese UDF das auch weiterreichen. Einfach mal probieren:


    https://www.autoitscript.com/f…325-tcp-udf-event-driven/

  • Hi chesstiger !


    Was mich etwas nachdenklich stimmt, ist folgender Post von Kip (Mai 2013) :

    https://www.autoitscript.com/f…=comments#comment-1074302

    Zitat

    Don't use this UDF.

    It is flawed. At the time of writing this I did not fully understand the underlying techniques.

    As a result it will seem to fail randomly.

    zu deutsch in etwa :

    Diese UDF nicht verwenden. Sie ist fehlerhaft. Zum Zeitpunkt der Erstellung habe ich die zugrunde liegenden Techniken nicht vollständig verstanden. Infolgedessen scheint sie zufällig fehlzuschlagen.


    Gruß Musashi

    "Die Definition von Wahnsinn ist, immer wieder das Gleiche zu tun und andere Ergebnisse zu erwarten." - Albert Einstein

  • @chesstiger


    Danke für den Tipp! Aufs erste macht es das, was es soll ... Registriert auf jeden Fall erstmalig für mich den Abbruch der Verbindung, wenn man sie beendet... Übrigens wie alle TCP-Android-Tools die ich verwende.


    Allerdings ist das nochmal zu differenzieren: Wenn ich den Linux-Server über das Terminalfenster auf dem Linux-PC schließe und dort wieder starten möchte, zeigt er erstmal, dass der Port noch belegt ist. Wenn ich dort via Kommandozeile den Port wieder frei gebe (fuser...), zeigt die Kip-UDF dann (!) sofort die abgebrochene Verbindung an

  • Ja, habe ich auch gelesen. Hatte aber noch nie Probleme mit dieser UDF. Verwende sie auch in Skripten, die 24/7 auf einem Server bei uns in der Firma laufen, von daher..

    Ok, Danke.

    Dass ein Ersteller in der Form von der Nutzung seiner UDF abrät, ist ja doch eher selten. Wenn es bei Dir aber läuft, dann langt mir das als 'Qualitätssiegel' völlig aus ^^.


    Gruß Musashi

    "Die Definition von Wahnsinn ist, immer wieder das Gleiche zu tun und andere Ergebnisse zu erwarten." - Albert Einstein

  • Ich habe das ganze Problem jetzt nochmal vereinfacht hier dargestellt - ohne die Kip-Version, weil ich gerne wissen würde, was ich hier falsch mache oder woran das liegt. Ich teste das gerade mit einem Android TCP-Server.


    Gehe ich in dem Server auf "disconnect" oder schließe ich ihn, wird das in dem Testprogramm unten nicht zurück gemeldet. Auch die Minimalisierung der While-Schleife ändert nichts.


    Nach allem, was ich bisher versucht habe, klappt die Kommunikation (hier die @error -Rückmeldung) - nach Killen des Servers - nur zwischen Autoit-Programmen. Bin gespannt, ob jemand findet, woran das liegt ...


  • Nach allem, was ich bisher versucht habe, klappt die Kommunikation (hier die @error -Rückmeldung) - nach Killen des Servers - nur zwischen Autoit-Programmen. Bin gespannt, ob jemand findet, woran das liegt ...

    Wir kennen die Implementation des Servers in der Android App nicht.

    Ich habe ein kleines C# Beispiel getestet was vernünftig die Verbindung schließt und dort schmeißt er mir direkt ein @error wenn ich die Anwendung beende.


    Es kommt also ganz auf die Implementation des Servers an, wenn du dich auf die nicht verlassen kannst, dann musst du Heartbeats senden, sonst hast du keine andere Möglichkeit.


  • Ich habe ein kleines C# Beispiel getestet was vernünftig die Verbindung schließt und dort schmeißt er mir direkt ein @error wenn ich die Anwendung beende.

    Du bekommst die Rückmeldung, wenn Du unplanmäßig die Verbindung killst (also die C# - Anwendung mittels Taskmanager killst)?

  • Du bekommst die Rückmeldung, wenn Du unplanmäßig die Verbindung killst (also die C# - Anwendung mittels Taskmanager killst)?

    Auch da bekomme ich eine Nachricht. Scheint als ob Windows die Verbindungen ordentlich aufräumt und beendet.

    Selbst wenn Windows das aber nicht machen würde sollte es nicht überraschen, dass dort kein Fehler geschmissen wird, weil eben die Verbindung nicht ordnungsgemäß beendet wurde.

    Da hast du nur die Möglichkeit Daten an den Client zu schicken und zu prüfen ob er noch aktiv ist.

  • Ok. Danke alpines! Ich belasse es mit der Kip-Variante. Die meldet den unvorhersehbaren Verbindungsabbruch. Läßts sich auch schön einbauen. Windows verhält sich hier zwischen Win-Geräten offensichtlich anders als gemischte Varianten (Linux-Win, Android-Linux, Android-Win). Aber wie gesagt: Die Kip-Implementierung klappt mit allen Standards.

  • @ alpines

    Hättest du eine Idee, wie man ressourcenschonend die heartbeates machen kann? Ich teste noch, verschiedenste Fehler abzufangen. Mit TCPSend und der Rückgabe über die WSAGetLastError sind vom WLAN-Abbruch über sämtliche andere Fehler diese handhabbar. Die Kip-Version bedarf einer Ergänzung, weil sie z.B. Peer-Abbruchfehler (WLAN) nicht registriert.


    Was hältst Du von sowas:


  • Du musst zwischen dem @ und dem Namen das Leerzeichen entfernen wenn du willst, das ich eine Benachrichtigung bekomme.


    Die Umsetzung an sich ist nicht übel, das kannst du so machen. Solltest aber immer beachten wann du dein Adlib registrierst um auch gültige Pakete zu senden.

    Das "" vor dem @LF kannst du weglassen, das ist nicht notwendig. Und noch 'ne Kleinigkeit wäre der Name der Funktion. Der Plural von Heartbeat schreibt sich Heartbeats.


    Ansonsten musst du vielleicht mit dem Timing noch rumspielen, ich weiß nicht in welchem Abstand du Pakete sendest/empfängst aber ansonsten schaut das eigentlich ok aus.