Hi Hsg,
ich habe mir das ganze gerade mal auf die schnelle angeschaut
und ein paar kleine Änderungen gemacht ohne Testmöglichkeit, deshalb ohne Gewähr auf Richtig.
Erstmal habe ich innerhalb der Procedure DisConnectAllClients
das Senden mit Try except gekapselt, damit auch alle Clients wirklich die Nachricht bekommen
und nicht wenn bei z.b. Client2 eine
Exception während des Senden auftritt und die restlichen Clients dann
nicht mehr benachrichtigt werden.
Des Weiteren habe ich LockList und UnlockList mit Try finally abgesichert !! Unbedingt zu empfehlen !!!
Delphi-Quellcode:
procedure TPDAServer.DisConnectAllClients();
var i : Integer;
oCont : TIdContext;
oList : TList;
begin
// Benachrichtige die Clients vom Ableben:
// ACHTUNG: Innerhalb der IDE tritt irgendwo eine EIdClosedSocked Exception auf
// das ist wohl ein bekanntes Problem, ist in der EXE wohl nicht der Fall!
if oServer <>
nil then begin
oList := oServer.Contexts.LockList;
try
if oList.Count > 0
then begin
for i:=0
to oList.Count -1
do begin
oCont := TIdContext(oList[i]);
if (oCont <>
nil)
and (oCont.Connection <>
nil)
then begin
try
// nach dem Aufruf von CheckDataOnSource kannst Du Dich auch auf die Property connected verlassen
oCont.Connection.AContext.Connection.IOHandler.CheckForDataOnSource(100);
if oCont.Connection.Connected
then begin
Info('
Aufforderung zur Abmeldung für Client: ' + GetHostName(oCont));
oCont.Connection.IOHandler.Writeln('
CLOSE_REQUEST@ ');
end;
// oCont.Connection.Disconnect(false);
except
on e:
exception do begin
{$IFDEF DEBUG}
OutputDebugString(PChar(e.Mesage));
{$ENDIF}
end;
end;
end;
// if oCont <> nil
end;
end;
finally
oServer.Contexts.UnlockList();
end;
end;
// if oServer <> null
end;
Weitere Änderung im OnExecute:
Delphi-Quellcode:
// .. snip
//AContext.Connection.IOHandler.CheckForDisconnect(False, True);
//AContext.Connection.CheckForGracefulDisconnect(False);
// Damit Exceptions auch ausgelöst und weitergereicht werden, geändert zu:
AContext.Connection.IOHandler.CheckForDisconnect(true, True);
AContext.Connection.CheckForGracefulDisconnect(true);
// Meiner Meinung nach sogar beides überflüssig an dieser Stelle
// Wenn's hier benutzt wird, dann mit Exception
// .. snip
Ein weiterer sehr entschiedener Punkt ist:
Wo wird DisConnectAllClients aufgerufen, in Deinem Sourcecode Auszug ist kein Aufruf davon zu finden!
Und gerade im Setter der Active Eigenschaft Deines Servers, solltest Du vorm setzen der Eigenschaft
Active = false, woher alle Clients benachrichtigen, das der Server heruntergefahen wird und die Clients
die Verbindung trennen sollen.
Delphi-Quellcode:
procedure TPDAServer.SetActive(const lAct: Boolean);
var
dtTimeout : TDateTime;
iClientCount : Integer;
// etwas unschön hier reingequescht, kann/darf gerne woanders positioniert werden
function getClientCount : Integer;
var oList : TList;
begin
oList := oServer.Contexts.LockList;
try
result := oList.Count;
finally
oServer.Contexts.UnlockList();
end;
end;
begin
if not lAct then begin
// Server soll beendet werden, vorher alle noch aktiven Clients benachrichtigen
DisConnectAllClients;
// maximalen Timeout berechnen, der auf Clients gewartet wird
dtTimeOut := now + 10/24/60/60; // jetzt + 10 Sekunden
iClientCount := getClientCount;
while (iClientCount > 0) and (now < dtTimeout) do begin
// Application.Processmessages; // eventuell bei Bedarf
Sleep(250); // warten ...
iClientCount := getClientCount;
end;
end;
oServer.Active := lAct;
end;
Das sollte Dein Problem jetzt aber lösen (hoff ich)
Greetz Data
Der Horizont vieler Menschen ist ein Kreis mit Radius Null, und das nennen sie ihren Standpunkt.