AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi TClientSocket verbraucht Ports (Fehler 10055)
Thema durchsuchen
Ansicht
Themen-Optionen

TClientSocket verbraucht Ports (Fehler 10055)

Ein Thema von spitzley · begonnen am 26. Jun 2005 · letzter Beitrag vom 3. Jul 2005
Antwort Antwort
spitzley

Registriert seit: 4. Jan 2005
2 Beiträge
 
#1

TClientSocket verbraucht Ports (Fehler 10055)

  Alt 26. Jun 2005, 10:49
Mein Problem ist folgendes:

(Betriebssystem Win XP prof.)

n TCP-Clients sollen einen TCP-Server connecten. Bei einem Verbindungsabriss sollen die Clients einen ReConnect bis zum Erfolg durchführen.
Die Reconnects werden pro Client über einen Timer durchgeführt:

Delphi-Quellcode:
procedure TNetRouter.OnGateway1ReconnectServerTimer(Sender: TObject);
begin
  if FGateway1Activate and not(FGateway1Connected) then
    begin
      if FGateway1AutoReconnect then
        begin
          inc(FGateway1NoOfConnectRetries);
          Gateway1TCPClientSock.Open;
        end;
      FGateway1ReconnectServerTimer.Enabled:=false;
      (Connect-Error schaltet Timer wieder ein)
    end;
end;
Bei jedem Reconnect (alle 3 Sek. pro Client) wird ein neuer Port verwendet und das mündet nach einiger Zeit, wenn alle Ports aufgebraucht sind, in einem Absturz (Fehler 10055).

Auch anderere Clients "fressen" Ports auf. Bsw. Hyperterminal, Indy-Demo-TCP-Client etc.
Das ganze scheint aber ein Win-Problem zu sein. Windows gibt die bereits verwendeten Ports nicht schnell genug wieder frei. So das Ergebnis einer Google-Recherche. Auch die gefundenen
Work-Arounds greifen nicht. (MaxUserPorts etc.)

Meine Frage also:
Kennt jemand eine Lösung für stabile Reconnects für viele TCP-Clients?

[edit=alcaeus]Delphi-Tags eingefuegt. In Zukunft bitte selbst machen. Danke Mfg, alcaeus[/edit]
  Mit Zitat antworten Zitat
Xanadu

Registriert seit: 8. Mai 2005
Ort: Schwäbisch Gmünd
20 Beiträge
 
Delphi 5 Enterprise
 
#2

Re: TClientSocket verbraucht Ports (Fehler 10055)

  Alt 3. Jul 2005, 03:01
Hi spitzley,

der Ordnunghalber würd ich beim Reconnecten im Fehlerfall aufräumen statt ständig nur weiter neu auf zu machen. Möglicherweise läuft der Client dann nicht mehr voll.

Und das gleiche würde ich bei der eigentlichen, abgebrochenen Verbindung auch mit ner Exception abfangen. Sprich: die alte Verbindung vor dem Reconnect auch zuerst schliessen bevor der Timer angemacht wird.

Im Weiteren würd ich den Timer langsam länger takten. Nachdem Du von mehr als einem Client sprichst feuerst Du sonst Deinen Server irgendwann nieder. Zwar ist sich jeder selbst der Wichtigste und will gleich wieder ran aber mit nem toten Pferd reitet es sich im Allgemeinen schlecht.

Delphi-Quellcode:
procedure TNetRouter.OnGateway1ReconnectServerTimer(Sender: TObject);
begin
  if FGateway1Activate and not(FGateway1Connected) then
    begin
      if FGateway1AutoReconnect then
        [b]try[/b]
          inc(FGateway1NoOfConnectRetries);
          Gateway1TCPClientSock.Open;
          [u]FGateway1ReconnectServerTimer.Interval:= 3000;[/u]
        [b]except
          HandleReConnectError;[/b]
        end;
      FGateway1ReconnectServerTimer.Enabled:=false;
      (Connect-Error schaltet Timer wieder ein)
    end;
end;

[b]Procedure TNetRouter.HandleReConnectError;
begin
  Gateway1TCPClientSock.Close;
  [u]FGateway1ReconnectServerTimer.Interval:= FGateway1ReconnectServerTimer.Interval + 1000;[/u]
end;[/b]
Have fun, Bernd
  Mit Zitat antworten Zitat
spitzley

Registriert seit: 4. Jan 2005
2 Beiträge
 
#3

Re: TClientSocket verbraucht Ports (Fehler 10055)

  Alt 3. Jul 2005, 12:43
Hallo Bernd !

Danke für Deine Antwort. Ich habe das Problem ähnlich Deinem Vorschlag gelöst:
Ein Retry-Counter verlangsamt dynamisch den Reconnect-Timer-Takt:

Delphi-Quellcode:
procedure TNetRouter.OnGateway1ReconnectServerTimer(Sender: TObject);
begin
  if FGateway1Activate and not(FGateway1Connected) then
    begin
      if FGateway1AutoReconnect then
        begin
          inc(FGateway1NoOfConnectRetries);
          CtrlDlg.NotifyGateway1Info(format('ReConnect %d',[FGateway1NoOfConnectRetries]), $0080FFFF);
          Gateway1TCPClientSock.Close;
          Gateway1TCPClientSock.Open;
        end;
      FGateway1ReconnectServerTimer.Enabled:=false;
      FGateway1ReconnectServerTimer.Interval:=FGateway1NoOfConnectRetries*ReconnectServerTimerIntervalFactor;
    end;
end;
Bei Connect-Mißerfolg startet der Error Handler den Timer erneut:

Delphi-Quellcode:
procedure TNetRouter.Gateway1TCPClientSockError(Sender: TObject; Socket: TCustomWinSocket;
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
   ErrorCode := 0;

   case ErrorEvent of
     eeGeneral:
       //Der Socket erhielt eine Fehlermeldung, die in keine der folgenden Kategorien paßt.
       CtrlDlg.NotifyGateway1Info('ClErr:unbek. Fehler', $0080FFFF);
     eeSend:
       //Beim Schreiben der Socket-Verbindung trat ein Fehler auf.
       CtrlDlg.NotifyGateway1Info('ClErr:Schreibfehler', $0080FFFF);
     eeReceive:
       //Beim Lesen der Socket-Verbindung trat ein Fehler auf.
       CtrlDlg.NotifyGateway1Info('ClErr:Lesefehler', $0080FFFF);
     TErrorEvent(6),eeConnect:
       //Bei Client-Sockets bedeutet dieser Wert, daß der Server nicht gefunden
       //wurde oder daß ein Problem auf dem Server das Öffnen der Verbindung
       //verhindert. Bei Server-Sockets bedeutet dieser Wert, daß eine
       //Client-Verbindungsanforderung, die bereits angenommen wurde,
       //nicht beendet werden kann.
       begin
         CtrlDlg.NotifyGateway1Info('ClErr:Keine Verbindung', clRed);
         if Gateway1AutoReconnect and Gateway1ActivateTCPClient then
           FGateway1ReconnectServerTimer.Enabled:=true;
       end;
     eeDisconnect:
       begin
         //Beim Schließen einer Verbindung trat ein Fehler auf.
         CtrlDlg.NotifyGateway1Info('ClErr:Disconnect', clRed);
         if Gateway1AutoReconnect and Gateway1ActivateTCPClient then
           FGateway1ReconnectServerTimer.Enabled:=true;
       end;
   end;
end;
Das ganze funktioniert sowohl bei mißglückten Connects (Client-Verbindungsaufbau,aber Server nicht gefunden) als auch bei Disconnects (Server-Absturz).

Was ich nicht verstehe, ist Folgendes:

Der Server läuft an einem DSL-Anschluss mit dynamischer IP. Ändert sich jetzt die IP nach einigen Stunden, dann
gibts es beim Server ein "normales" Disconnect-Event und er trennt sich von seinen Clients.
Die Clients kriegen nichts vom IP-Wechsel mit und meinen weiterhin, sie seien verbunden.
(Es fließen keine Daten zum Server ! Das würde die Clients den Zusammenbruch merken lassen)

Delphi-Quellcode:
procedure TNetRouter.Gateway1TCPServSockClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  try
  FConnectedTCPClient:=ConnectedTCPClientBySocket(FGateway1ConnectedTCPClientList,Socket);
  RemoveConnectedTCPClient(FGateway1ConnectedTCPClientList,Socket);
  CtrlDlg.NotifyGateway1Info('Noch '+IntToStr(FGateway1ConnectedTCPClientList.Count)+' Teilnehmer', $0080FFFF);
  Log('GW1,TCP-Server,getrennt von '+Socket.RemoteAddress+':'+IntToStr(Socket.RemotePort));
  Gateway1Connected:=FGateway1ConnectedTCPClientList.Count<>0;
  except end;
end;
Es gibt kein Error-Event, wo ich in diesem Handler auf die ungewollte Trennung reagiern könnte:

Delphi-Quellcode:
procedure TNetRouter.Gateway1TCPServSockClientError(Sender: TObject; Socket: TCustomWinSocket;
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
   ErrorCode := 0;
   case ErrorEvent of
     eeGeneral:
       //Der Socket erhielt eine Fehlermeldung, die in keine der folgenden Kategorien paßt.
       CtrlDlg.NotifyGateway1Info('SvErr:unbek. Fehler', $0080FFFF);
     eeSend:
       //Beim Schreiben der Socket-Verbindung trat ein Fehler auf.
       CtrlDlg.NotifyGateway1Info('SvErr:Schreibfehler', $0080FFFF);
     eeReceive:
       //Beim Lesen der Socket-Verbindung trat ein Fehler auf.
       CtrlDlg.NotifyGateway1Info('SvErr:Lesefehler', $0080FFFF);
     eeConnect:
       //Bei Client-Sockets bedeutet dieser Wert, daß der Server nicht gefunden
       //wurde oder daß ein Problem auf dem Server das Öffnen der Verbindung
       //verhindert. Bei Server-Sockets bedeutet dieser Wert, daß eine
       //Client-Verbindungsanforderung, die bereits angenommen wurde,
       //nicht beendet werden kann.
       CtrlDlg.NotifyGateway1Info('SvErr:Verbindungsaufbau', $0080FFFF);
     eeDisconnect:
       begin
         //Beim Schließen einer Verbindung trat ein Fehler auf.
         RemoveConnectedTCPClient(FGateway1ConnectedTCPClientList,Socket);
         CtrlDlg.NotifyGateway1Info('SvErr: Noch '+IntToStr(FGateway1ConnectedTCPClientList.Count)+' Teilnehmer', $0080FFFF);
       end;
     eeAccept:
       //Beim Übernehmen einer Client-Verbindungsanforderung trat ein Fehler auf (nur bei Server-Sockets).
       CtrlDlg.NotifyGateway1Info('SvErr:Verb.anford.', $0080FFFF);
   end;
end;
Warum gibts da kein Event bei den Clients ?

Mein WorlAround wäre: Die Clients prüfen periodisch per DNS-Resolving, ob die Server IP sich geändert hat.

Delphi-Quellcode:
function GetIPAddressByDNSQuery(URL, DNSServer : string):string;
var
  IdDNSResolver: TIdDNSResolver;
  I: Integer;
begin
  Result:='';
  IdDNSResolver:=TIdDNSResolver.Create(nil);

  IdDNSResolver.ReceiveTimeout:=6000; //6 Sekunden bis zum Timeout !!!!!

  IdDNSResolver.Host := DNSServer;
  try
    IdDNSResolver.Active := True;
    try
      IdDNSResolver.QueryResult.Clear;
      IdDNSResolver.QueryRecords := [qtSTAR];
      IdDNSResolver.Resolve(URL);
      if IdDNSResolver.QueryResult.Count<>0 then
      for I := 0 to IdDNSResolver.QueryResult.Count-1 do
      begin
        case IdDNSResolver.QueryResult.Items[I].RecType of
        qtA:
          begin
            Result:=TARecord(IdDNSResolver.QueryResult.Items[I]).IPAddress;
            break;
          end;
        end;
      end;
    except
    end;
  finally
    IdDNSResolver.Active := False;
    IdDNSResolver.Free;
  end;
end;
Das erscheint mir aber aufwendig und unelegant.

Wie sonst können nichtsendende Clients den Kontaktverlust zum Server bemerken ?

Idee ?


Grüße

Kurt Spitzley
  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 15:44 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