AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Socket Error 10054 Connection reset by peer - wie behandeln?
Thema durchsuchen
Ansicht
Themen-Optionen

Socket Error 10054 Connection reset by peer - wie behandeln?

Ein Thema von Medium · begonnen am 5. Nov 2015 · letzter Beitrag vom 7. Nov 2015
Antwort Antwort
Seite 1 von 2  1 2      
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#1

Socket Error 10054 Connection reset by peer - wie behandeln?

  Alt 5. Nov 2015, 11:57
Huhu Leute,

ich habe ein Programm, mit dem ich via TCP (Indy) Anfragen an ein paar Geräte sende (keine PCs, sondern Modbus->TCP Gateways), um Daten von diesen anzufordern. Das klappt auch alles recht gut, bis auf bei einem der Gateways. Dieses kommt, teils nach wenigen Minuten, teils erst nach einem Tag, auf die Idee die Connection zu resetten, was zu o.g. Meldung bei mir führt.
Ab dieser Meldung kann ich mit dem Gateway nicht mehr kommunizieren. Als Lösung dafür habe ich es so programmiert, dass ich bei Auftreten des Fehler die komplette TIdTCPClient Instanz lösche und neu instanziiere, um einen ganz frischen neuen Socket zu bekommen. Leider gibt es mit der neuen Instanz genau dasselbe Problem: Es geht sofort mit Error 10054 weiter.

Aber! Starte ich mein Programm neu, geht es völlig problemlos!

Was macht ein Programmneustart mehr, was ein IdTCPClient.Free; nicht zu leisten vermag? An den Gateways kann ich leider nichts machen. Ich muss das Problem in meinem Programm behandeln, was ja scheinbar möglich sein muss, wenn ein Neustart (nur des Programms, nicht des ganzen PCs) funktioniert.

Ein verknüpftes Problem: Ich fange den Fehler in einem try..except ab. Aber das Fehlerfenster wird trotzdem generiert, auch außerhalb der IDE. Wie kann ich das unterdrücken? Mein Programm soll nachher 24/7 unbeaufsichtigt laufen, und da wäre es extrem unschön wenn es diese Meldungen ansammelt.


Besten Dank im Voraus!
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Socket Error 10054 Connection reset by peer - wie behandeln?

  Alt 5. Nov 2015, 12:25
Detailfrage:
Die TIdTCPClient-Instanz läuft in einen eigenen Thread?
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#3

AW: Socket Error 10054 Connection reset by peer - wie behandeln?

  Alt 5. Nov 2015, 16:47
Ich bin leider erst jetzt wieder im Büro, sorry. Die Instanzen laufen im Kontext des Mainthreads, da es für das Programm recht egal war, dass es zwischendurch für ein paar ms nicht reagiert. 2 von den 3 Verbindungen laufen auch ohne Probleme.

Edit: Jetzt ist die VM auch hochgefahren, so dass ich Code posten kann:
Delphi-Quellcode:
// TCP Komponenten Erstellen
procedure TValueGroup.CreateTCP;
begin
  if Assigned(FTCP) then
  begin
    if FTCP.Connected then
      FTCP.Disconnect(false);
    FreeAndNil(FTCP);
  end;
  FTCP := TIdTCPClient.Create;
  FTCP.IOHandler := TIdIOHandlerStack.Create;
  FTCP.IOHandler.ReadTimeout := 1000;
  FTCP.Host := FIP;
  FTCP.Port := FPort;
  FTCP.OnStatus := OnTCPStatus;
end;
Delphi-Quellcode:
// Verbindungsherstellung
procedure TValueGroup.ConnectToGateway;
begin
  try
    FTCP.ConnectTimeout := 100;
    if not FTCP.Connected then FTCP.Connect();
  except
    on e: Exception do
    begin
      frmTCPLog.Add(FTCP.Host+': Connect failed. Recreating.');
      try
        CreateTCP;
      except
      end;
    end;
  end;
end;
Delphi-Quellcode:
// Meine Daten-Refresh Prozedur
procedure TValueGroup.RefreshData;
var
  remainingBytes: Integer;
  sAdr: Integer;
begin
  remainingBytes := FMaxAddress+4 + 2;
  SetLength(FBuffer, remainingBytes);
  try
    if not FTCP.Connected then
      ConnectToGateway;

    sAdr := 0;
    while remainingBytes > 255 do
    begin
      FRequestBuffer[1] := Byte(sAdr shr 8);
      FRequestBuffer[2] := Byte(sAdr and $FF);
      FRequestBuffer[4] := 255;
      SendBuffer(TCP, RequestBuffer);
      ReceiveBuffer(TCP, FBuffer, sAdr, 255);
      dec(remainingBytes, 255);
      inc(sAdr, 255);
    end;

    FRequestBuffer[1] := Byte(sAdr shr 8);
    FRequestBuffer[2] := Byte(sAdr and $FF);
    FRequestBuffer[4] := Byte(remainingBytes and $FF);
    SendBuffer(TCP, RequestBuffer);
    ReceiveBuffer(TCP, FBuffer, sAdr, remainingBytes);

    BufferToValues;
  except
    on e: Exception do
    begin
      frmTCPLog.Add(FTCP.Host+' Recovering from "'+e.Message+'"');
      CreateTCP;
    end;
  end;
end;
Der Fehler der auftritt, ist der in diesem except-Block der zuletzt gezeigten Prozedur. Das heisst das bloße Connect geht, aber die Kommunikation führt zum Fehler. Aber halt nur bei einem Partner, und nach unbestimmter Zeit tadelloser Funktion.

Der Vollständigkeit halbar noch die Send- und RecieveBuffer Funktionen:
Delphi-Quellcode:
function TValueGroup.ReceiveBuffer(AClient: TIdTCPClient; var ABuffer: TBytes; aOffset, aLength: Integer): Boolean;
var
  b: TBytes;
begin
  Result := True;
  try
    SetLength(b, aLength);
    FillChar(b[0], aLength, 0);
    AClient.IOHandler.ReadBytes(b, -1, false);
    Move(b[0], ABuffer[aOffset], aLength);
  except
    Result := False;
  end;
end;

function TValueGroup.SendBuffer(AClient: TIdTCPClient; ABuffer: TBytes): Boolean;
begin
  try
    Result := True;
    try
      AClient.IOHandler.WriteBufferOpen;
      AClient.IOHandler.Write(ABuffer);
      AClient.IOHandler.WriteBufferFlush;
    finally
      AClient.IOHandler.WriteBufferClose;
    end;
  except
    Result := False;
  end;
end;
Der OnStatus-Handler loggt nur die Statusänderungen und unternimmt sonst nichts.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)

Geändert von Medium ( 5. Nov 2015 um 16:59 Uhr)
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#4

AW: Socket Error 10054 Connection reset by peer - wie behandeln?

  Alt 5. Nov 2015, 21:58
Als Lösung dafür habe ich es so programmiert, dass ich bei Auftreten des Fehler die komplette TIdTCPClient Instanz lösche und neu instanziiere, um einen ganz frischen neuen Socket zu bekommen. Leider gibt es mit der neuen Instanz genau dasselbe Problem: Es geht sofort mit Error 10054 weiter.

Aber! Starte ich mein Programm neu, geht es völlig problemlos!

Was macht ein Programmneustart mehr, was ein IdTCPClient.Free; nicht zu leisten vermag?
Das ist in der Tat seltsam. Ich kann es mir nur damit erklären, dass es etwas mit der Zeit zu tun hat, die zwischen dem Free und dem Neuerzeugen vergeht. Es gibt das manchmal bei Servern, dass eine Verbindung, nachdem sie beendet (besser gesagt abgebrochen) wurde, erst mal eine Weile weiter bestehen bleibt (TIME-WAIT). Während der alte Socket im TIME-WAIT-Zustand ist, kann man keinen neuen Socket auf dem Port erstellen.

Eigentlich sollte das nach meinem begrenzten Wissen nur bei Servern ein Problem sein und nicht bei Clients. Aber ich könnte mir vorstellen, dass es dennoch irgendwas damit zu tun hat.¹ Du kannst ja mal zum Testen nach dem Free ein Sleep o.ä. einbauen, das ungefähr so lange dauert wie ein Programmneustart dauern würde.

Oder kann es sein, dass irgendeine Firewall oder Virenscanner auf dem Client verrückt spielt?

Edit ¹: Jetzt wo ich noch mal darüber nachdenke: Vermutlich ist der Server oder die Verbindung zum Server irgendwie abgeschmiert (wurde nicht korrekt beendet), und der Socket bleibt deshalb im TIME-WAIT-Zustand. Der Server versucht einen neuen Listener-Socket zu erstellen, kann er aber nicht, weil der alte Socket noch im TIME-WAIT-Zustand ist. Natürlich lässt das Betriebssystem des Servers keine neuen Verbindungen zu dem alten Socket zu, weil der ja tot ist, weshalb die Verbindungsversuche deines Clients mit "Connection reset by peer" zurückgewiesen werden. Wenn du eine Weile wartest, ist der alte Socket weg, der Server kann einen neuen erstellen, und dann klappen die Verbindungen wieder.

Geändert von Namenloser ( 5. Nov 2015 um 22:09 Uhr)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#5

AW: Socket Error 10054 Connection reset by peer - wie behandeln?

  Alt 5. Nov 2015, 22:12
FW oder Virenscanner kann ich ausschließen, aber deine erste Idee klingt gar nicht mal so schlecht! Mein Programm braucht in der Tat ein paar Sekunden zum Start, da erst noch ein größeres TreeView aus der DB befüllt wird nebst anderem Init-Krams. Ich werde morgen testweise eine Pause einbauen, ich hoffe dass sich das Problem jetzt nicht zu rar zum brauchbar testen macht.

Ich kenne das auch noch von Siemens SPSen, die nach (auch regulärem) Trennen der Socket-Verbindung zu projektierten Fetch/Write Ports rund 20s brauchten bis sie wieder eiine Verbindung annahmen. Aber seit wir auf das S7Online Protokoll via libnodave umgestiegen sind, kein Problem mehr. Von daher absolut plausibel. Bin gespannt.
Das einzige was mich ein wenig pessimistisch stimmt ist, dass ich heute morgen im Log Verbindungsversuche durchgehend von 4:30 bis 9:00 Uhr hatte, und ich das Prgoramm dann beendet habe. Ich hoffe, dass das Gateway dann aktiv geblockt hat wegen zu früher Anfragen oder so. Was aber auch dämlich wäre. Egal, probieren! Danke!

Edit wegen deinem Edit: Klingt durchaus auch plausibel. Ich weiss jetzt nicht wie genau die Gateways intern funktionieren - Mini-PCs sind es definitiv nicht - aber vielleicht haben die ein vergleichbares Problem. Das könnte auch ggf. erklären warum schnell wiederholte Anfragen den Zustand einfrieren: Vielleicht hat der "tote" Socket noch eine Karenzzeit nach dem er das Reset geschickt hat, welche ich so immer neu aufziehen würde. Probieren!
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)

Geändert von Medium ( 5. Nov 2015 um 22:16 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: Socket Error 10054 Connection reset by peer - wie behandeln?

  Alt 5. Nov 2015, 22:52
Hast du auch schon versucht den InputBuffer vom IOHandler zu löschen, so wie hier beschrieben
http://stackoverflow.com/a/10523444/1744164

Also so in etwa
Delphi-Quellcode:
// TCP Komponenten Erstellen
procedure TValueGroup.CreateTCP;
var
  tmp: TIdTCPClient;
begin
  if Assigned( FTCP )
  then
    begin
      if FTCP.Connected
      then
        try
          FTCP.Disconnect( false ); // Hier kommt u.U. der Socket Error 10054
        except
          on e: Exception do
            frmTCPLog.Add( FTCP.Host + ': Error on Disconnect "' + e.ClassName + ': ' + e.Message + '". Do not care, we are recreating the connection' );
        end;
      if Assigned( FTCP.IOHandler )
      then
        FTCP.IOHandler.InputBuffer.Clear;
      FreeAndNil( FTCP );
    end;
  // Hier sollte eigentlich kein Fehler passieren,
  // aber falls doch, dann so absichern
  tmp := TIdTCPClient.Create;
  try
    tmp.IOHandler := TIdIOHandlerStack.Create;
    tmp.IOHandler.ReadTimeout := 1000;
    tmp.Host := FIP;
    tmp.Port := FPort;
    tmp.OnStatus := OnTCPStatus;

    FTCP := tmp;
    tmp := nil;
  finally
    tmp.Free;
  end;
end;

// Verbindungsherstellung
procedure TValueGroup.ConnectToGateway;
begin
  try
    FTCP.ConnectTimeout := 100;
    if not FTCP.Connected
    then
      FTCP.Connect( );
  except
    on e: Exception do
      begin
        // Exception komplett mitloggen
        frmTCPLog.Add( FTCP.Host + ': Connect failed with "' e.ClassName + ': ' + e.Message + '" Recreating.' );
        // try
        CreateTCP;
        // except
        // end;
      end;
  end;
end;

// Meine Daten-Refresh Prozedur
procedure TValueGroup.RefreshData;

var
  remainingBytes: Integer;
  sAdr : Integer;
begin
  remainingBytes := FMaxAddress + 4 + 2;
  SetLength( FBuffer, remainingBytes );
  try
    if not FTCP.Connected
    then
      ConnectToGateway;

    sAdr := 0;
    while remainingBytes > 255 do
      begin
        FRequestBuffer[ 1 ] := Byte( sAdr shr 8 );
        FRequestBuffer[ 2 ] := Byte( sAdr and $FF );
        FRequestBuffer[ 4 ] := 255;
        SendBuffer( TCP, RequestBuffer );
        ReceiveBuffer( TCP, FBuffer, sAdr, 255 );
        dec( remainingBytes, 255 );
        inc( sAdr, 255 );
      end;

    FRequestBuffer[ 1 ] := Byte( sAdr shr 8 );
    FRequestBuffer[ 2 ] := Byte( sAdr and $FF );
    FRequestBuffer[ 4 ] := Byte( remainingBytes and $FF );
    SendBuffer( TCP, RequestBuffer );
    ReceiveBuffer( TCP, FBuffer, sAdr, remainingBytes );

    BufferToValues;
  except
    on e: Exception do
      begin
        // Exception komplett mitloggen
        frmTCPLog.Add( FTCP.Host + ': Recovering from "' + e.ClassName + ': ' + e.Message + '"' );
        CreateTCP;
      end;
  end;
end;
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo ( 5. Nov 2015 um 23:16 Uhr)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#7

AW: Socket Error 10054 Connection reset by peer - wie behandeln?

  Alt 5. Nov 2015, 23:07
Über den SO bin ich bei meiner Suche auch gestolpert, ja . Das Neuerstellen der TIdTCPClient Komponente (inkl. ihres IOHandlers) sollte das durchaus erledigen. Aber ich habe davor tatsächlich das Stück Code aus der Antwort dort probiert. Leider ohne Erfolg. (Durch den Post bin ich erst auf die Idee gekommen, Disconnect() mit dem Parameter aufzurufen.) Trotzdem danke für das Interesse!!
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#8

AW: Socket Error 10054 Connection reset by peer - wie behandeln?

  Alt 6. Nov 2015, 07:35
ich hatte vor Jahren mit Delphi im SPS-Umfeld zu tun. Ich kann mich erinnern, das gleiche Problem gehabt zu haben, woraufhin ich bei jeder TCP-Zicke das Programm gnadenlos beendet habe (Halt). Durch einen Neustart und anschließendem reconnect war das Problem dauerhaft gelöst. Der Neustart war einfach eine Endlosschleife in einer Batchdatei
Code:
:Loop
MeinProgramm.EXE
Goto Loop
Mir war und ist klar, das diese Art der Lösung ziemlich unprofessionell ist. Aber seit dieser Maßnahme ist Ruhe im Karton-

Geändert von Dejan Vu ( 6. Nov 2015 um 07:39 Uhr)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#9

AW: Socket Error 10054 Connection reset by peer - wie behandeln?

  Alt 7. Nov 2015, 01:17
Ich bin vorhin letztlich wieder auf UDP Kommunikation gegangen hier, wo das kein Problem ist. Ursprünglich bin ich von UDP zu TCP gewechselt, weil ich den Eindruck hatte, dass ich u.U. die Antworten in mehreren Paketen bekomme, die ich leider dank fehlender ID im Protokoll nicht einer spezifischen Anfrage zuordnen kann. TCP ist was solches Handshaking angeht ja etwas verlässlicher.
Aber ich habe meinen Fehler gefunden, und ja: Er war dämlich. In der Doku von den Gateways steht, dass ich von deren internem Array immer je 1000 Werte am Stück abfragen kann. Also habe ich das getan. Allerdings hieß "Wert" bei denen "Byte", bei mir aber "Single"... ich habe einfach 4x zu große Anforderungen geschickt, was meine Lücken in den Daten erklärt. Autsch!

Ergo: Kleinere Anfragen, auf deren Antworten ich brav warte und sie jeweils zusammen stückel, und schon ist alles paletti via UDP. Ich vermute schon fast, dass mich das Gateway per TCP ab und zu "rausgeworfen" haz, weil es irgendwann gemerkt hat, dass die Request-Buffer nach zu viel gefragt haben. (Bei den anderen 2 Gateways erfrage ich weniger, aber dennoch >1000 am Stück. Weiss der Geier warum dieses eine empfindlicher gewesen sein könnte.) Aber das werde ich nicht weiter erforschen, die ganze Nummer hat jetzt schon WEIT mehr Zeit und Nerven gekostet als man jemals zugeben dürfte.

Saß der Fehler doch mal wieder vor dem Bildschirm. Verdammt. (Auch wenn die Frage, wie man mit einem vom Peer gesendeten Reset am besten umgeht prinzipiell nicht ohne Relevanz ist.)

Vielen Dank nochmals an alle hier!!
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#10

AW: Socket Error 10054 Connection reset by peer - wie behandeln?

  Alt 7. Nov 2015, 09:28
Du musst dich aber nicht wundern, wenn von deinen UDP Paketen nicht immer alle ankommen.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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:16 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