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