![]() |
Abfragen ob eine Variable oder die Referenz noch existiert
Hallo,
hoffe der Titel ist für das Problem was ich habe richtig gewählt. Das Try / Except ist für mich jetzt nur eine Lösung, damit das Programm nicht ständig hängen bleibt.
Delphi-Quellcode:
AClient enthällt einen Socket und einen String;
try
while (Pos(EOCommand, AClient.Buffer) > 0) do begin Index := Pos(EOCommand, AClient.Buffer); DCFrame := Copy(AClient.Buffer, 1, Index + 4); AClient.Buffer := Copy(AClient.Buffer, Index + 5, Length(AClient.Buffer)); Parse_DCFrame(AClient, DCFrame); end; except Exit; end; Das klappt alles ohne Probleme solange nicht versucht wird das sich ein Benutzer doppelt einloggt. Meldet sich ein Benutzer ein zweites mal an wird in der Procedure OnClientDisconnet AClient freigegeben, danach springt er wieder in die Schleife und da Existiert "AClient" eigentlich nicht mehr, der Debugger sagt da so schön "nicht verfügbarer Wert" zu. Kann man irgendwie darauf Prüfen oder ex mit einer besseren Lösung als einem Try / Except abzufangen? Würde ungerne alles umbauen damit ich ihn nil setzen kann, das wäre so ein wenig zu viel was ich ändern müsste. Hilfe :) Gruß Dsn |
Re: Abfragen ob eine Variable oder die Referenz noch existie
Guten Morgen,
kannst Du nicht AClient auf nil überprüfen? Oder AClient mit Assigned abfragen?
Delphi-Quellcode:
Grüße
if Assigned(AClient) then
Klaus |
Re: Abfragen ob eine Variable oder die Referenz noch existie
Delphi-Quellcode:
Problem ist wie baue ich es in diese Schleife mit ein.
try
while (Pos(EOCommand, AClient.Buffer) > 0) do begin Index := Pos(EOCommand, AClient.Buffer); DCFrame := Copy(AClient.Buffer, 1, Index + 4); // +4 ersetzten durch Length(EOCommand) AClient.Buffer := Copy(AClient.Buffer, Index + 5, Length(AClient.Buffer)); // +5 ersetzen Parse_DCFrame(AClient, DCFrame); end; except Exit; end; Im Schleifenkopf geht es nicht da er dort ja auch gleich auf den String zugreift. ich könnte es aber mal so testen
Delphi-Quellcode:
Falls das nicht klappt, wüsste ich aber auch icht weiter auf anhieb.
try
while assigned(AClient) do begin if (Pos(EOCommand, AClient.Buffer) = 0) then Exit; Index := Pos(EOCommand, AClient.Buffer); DCFrame := Copy(AClient.Buffer, 1, Index + 4); // +4 ersetzten durch Length(EOCommand) AClient.Buffer := Copy(AClient.Buffer, Index + 5, Length(AClient.Buffer)); // +5 ersetzen Parse_DCFrame(AClient, DCFrame); end; except Exit; end; |
Re: Abfragen ob eine Variable oder die Referenz noch existie
Vielleicht so:
Delphi-Quellcode:
oder so:
if Assigned(AClient) then
begin while (Pos(EOCommand, AClient.Buffer) > 0) do begin Index := Pos(EOCommand, AClient.Buffer); DCFrame := Copy(AClient.Buffer, 1, Index + 4); AClient.Buffer := Copy(AClient.Buffer, Index + 5, Length(AClient.Buffer)); Parse_DCFrame(AClient, DCFrame); end; end;
Delphi-Quellcode:
Grüße
while ((Assigned(AClient)) AND(Pos(EOCommand, AClient.Buffer) > 0)) do begin
Index := Pos(EOCommand, AClient.Buffer); DCFrame := Copy(AClient.Buffer, 1, Index + 4); AClient.Buffer := Copy(AClient.Buffer, Index + 5, Length(AClient.Buffer)); Parse_DCFrame(AClient, DCFrame); end; Klaus |
Re: Abfragen ob eine Variable oder die Referenz noch existie
Liste der Anhänge anzeigen (Anzahl: 1)
Deine Erste Methode würde glaube ich nicht viel Bringen da er nur beim ersten mal Prüft ob der AClient zugewisen ist.
Die untere Methode habe ich auch ausprobiert klappt ebenfalls nicht. Habe noch etwas anderes versucht und dann brauch ich dazu mal eine erklärung bitte wie das zustande kommt.
Delphi-Quellcode:
Bin das mit dem Debugger durchgegangen.
if AClient.Buffer > '' then begin
while (Pos(EOCommand, AClient.Buffer) > 0) do begin Index := Pos(EOCommand, AClient.Buffer); DCFrame := Copy(AClient.Buffer, 1, Index + 4); // +4 ersetzten durch Length(EOCommand) AClient.Buffer := Copy(AClient.Buffer, Index + 5, Length(AClient.Buffer)); // +5 ersetzen Parse_DCFrame(AClient, DCFrame); if not Assigned(AClient) then Exit; if AClient.Buffer = '' then Exit; end; Wenn ich über Assigned(AClient) fahre steht dort -> Nicht verfügbarer Wert Im Debug-Insprektor jedoch sind noch alle Daten vorhanden. Versuche ich das ganze mit AClient.Buffer -> Zitat:
|
Re: Abfragen ob eine Variable oder die Referenz noch existie
Delphi-Quellcode:
try
while assigned(AClient) and (Pos(EOCommand, AClient.Buffer) > 0) do begin Index := Pos(EOCommand, AClient.Buffer); DCFrame := Copy(AClient.Buffer, 1, Index + 4); AClient.Buffer := Copy(AClient.Buffer, Index + 5, Length(AClient.Buffer)); Parse_DCFrame(AClient, DCFrame); end; except Exit; end; Zitat:
|
Re: Abfragen ob eine Variable oder die Referenz noch existie
AClient ist in dem Fall nur ein Item aus einer Collection.
Wenn ich sie auf nil setze müsste sie doch auch nachdem der Socket getrennt wurde noch vorhanden sein oder verstehe ich das da etwas falsch?
Delphi-Quellcode:
Klappt das ohne Probleme wenn ich das Item von FClients aus nil setze?
procedure TDC_SPA.FSocketClientRead(Sender: TObject;
Socket: TCustomWinSocket); var Index: Integer; AClient: TClient; DCFrame: String; begin if FClients.FindSocket(Socket, Index) then begin AClient := FClients.Client[Index]; AClient.Buffer := AClient.Buffer + Socket.ReceiveText; AClient.Buffer := StringReplace(AClient.Buffer, #$d#$a, LineFeed, [rfReplaceAll]); if AClient.Buffer > '' then begin while (Pos(EOCommand, AClient.Buffer) > 0) do begin Index := Pos(EOCommand, AClient.Buffer); DCFrame := Copy(AClient.Buffer, 1, Index + 4); // +4 ersetzten durch Length(EOCommand) AClient.Buffer := Copy(AClient.Buffer, Index + 5, Length(AClient.Buffer)); // +5 ersetzen Parse_DCFrame(AClient, DCFrame); if not Assigned(AClient) then Exit; if AClient.Buffer = '' then Exit; if AClient.SID = 0 then Exit; end; end; end; end; procedure TDC_SPA.Parse_DCFrame(AClient: TClient; AFrame: String); var Framelist: TFramelist; Command: Integer; AUser: TUser; Index: Integer; begin if Assigned(FOnRawData) then FOnRawData(Self, rsIn, AClient.SID, AFrame); [...] case Command of // Kommandoframe auswerten CMD_AUTH: HandleLogin(AClient, Framelist); // Anmelden CMD_PONG: HandlePong(AClient, Framelist); // Pong CMD_SEND_USER: HandleUserMessage(AClient, FrameList); // Nachricht an einen Benutzer // Alle Commands > 100 werden extern gehandled; else begin // Sicherstellen das das Command über 100 liegt if Command < 100 then Exit; // Nur wenn der Socket einem Benutzer zugeordnet werden kann fortfahren if Users.FindSocket(AClient.Socket, Index) then AUser := Users.User[Index] else Exit; // Übergabe an Extern if Assigned(FOnCommand) then FOnCommand(Self, AUser, Command, Framelist); end; end; Framelist.Free; end; procedure TDC_SPA.HandleLogin(AClient: TClient; FrameList: TFrameList); var Index: Integer; AUser: TUser; AuthVal: Boolean; begin if Framelist.Count <> 6 then // Anzuahl der Frames MUSS 6 sein begin SendMessage(AClient.Socket, CMD_LOGIN_FAIL, 'Login Error. Not enough parameters'); // Fehlermeldung falls ungültig AClient.Socket.Close; // Socket freigeben Exit; end; if Not Users.FindUser( FrameList.Frames[1].Frame, Index ) then begin AUser := FUsers.AddConnection(AClient.Socket); AUser.SID := AClient.SID; AUser.LoginTime := Now; AUser.LPStamp := TimeStamp; AUser.Address := FrameList.Frames[3].Frame; AUser.User := FrameList.Frames[1].Frame; AUser.Name := FrameList.Frames[2].Frame; AUser.Pass := Framelist.Frames[4].Frame; if Assigned(FAuthData) then FAuthData(Self, AUser, AuthVal) else AuthVal := True; AUser.Authed := AuthVal; if AuthVal then begin SendMessage(AUser.Socket, CMD_LOGIN_OK, 'Logged on'); SendUserlist(AUser, ucsLogin); if Assigned(FConnectionsStatus) then FConnectionsStatus(Self, FClients.Count, FUsers.Count); end else begin SendMessage(AUser.Socket, CMD_LOGIN_FAIL, 'Login Disabled'); AUser.Socket.Close; // Verbindung trennen end; end else begin SendMessage(AClient.Socket, CMD_USER_IN_USE, 'User allready connected'); // Benutzer bereits verbunden AClient.Socket.Close; // Verbindung trennen end; end; procedure TDC_SPA.FSocketClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); var Index: Integer; TmpUser: TUser; SID: Integer; begin if FUsers.FindSocket(Socket, Index) then begin TmpUser := FUsers.User[Index]; SID := TmpUser.SID; TmpUser.Free; end; if FClients.FindSocket(Socket, Index) then begin FClients.Client[Index].SID := 0; // Nutze ich nun zur Prüfung ob der Client noch vorhanden ist, damit gehts ohne Fehler FClients.Client[Index].Free; // <-- Hier wird das Item in dem Fall der Inhalt aus AClient freigegeben end; if Assigned(FConnectionsStatus) then FConnectionsStatus(Self, FClients.Count, FUsers.Count); // Clients über die veränderung benachrichtigen end; |
Re: Abfragen ob eine Variable oder die Referenz noch existie
Einfach mal meine Änderungen und Kommentare beachten...
Delphi-Quellcode:
Ok, alles mit dem Bold-Tag [b] beachten...
procedure TDC_SPA.FSocketClientRead(Sender: TObject; Socket: TCustomWinSocket);
var Index: Integer; AClient: TClient; DCFrame: String; begin if FClients.FindSocket(Socket, Index) then begin AClient := FClients.Client[Index]; AClient.Buffer := AClient.Buffer + Socket.ReceiveText; AClient.Buffer := StringReplace(AClient.Buffer, #$d#$a, LineFeed, [rfReplaceAll]); if AClient.Buffer > '' then begin while (Pos(EOCommand, AClient.Buffer) > 0) do begin Index := Pos(EOCommand, AClient.Buffer); DCFrame := Copy(AClient.Buffer, 1, Index + 4); // +4 ersetzten durch Length(EOCommand) AClient.Buffer := Copy(AClient.Buffer, Index + 5, Length(AClient.Buffer)); // +5 ersetzen Parse_DCFrame(AClient, DCFrame); if not Assigned(AClient) then Exit; [b]// break würde reichen...[/b] if AClient.Buffer = '' then Exit; [b]// break würde reichen...[/b] if AClient.SID = 0 then Exit; [b]// break würde reichen...[/b] end; end; end; end; procedure TDC_SPA.Parse_DCFrame(AClient: TClient; AFrame: String); var Framelist: TFramelist; Command: Integer; AUser: TUser; Index: Integer; begin if Assigned(FOnRawData) then FOnRawData(Self, rsIn, AClient.SID, AFrame); [...] case Command of // Kommandoframe auswerten CMD_AUTH: HandleLogin(AClient, Framelist); // Anmelden CMD_PONG: HandlePong(AClient, Framelist); // Pong CMD_SEND_USER: HandleUserMessage(AClient, FrameList); // Nachricht an einen Benutzer // Alle Commands > 100 werden extern gehandled; else begin // Sicherstellen das das Command über 100 liegt if Command < 100 then Exit; [b]// was ist mit der Framelist? Speicherleck?[/b] // Nur wenn der Socket einem Benutzer zugeordnet werden kann fortfahren if Users.FindSocket(AClient.Socket, Index) then AUser := Users.User[Index] else Exit; [b]// was ist mit der Framelist? Speicherleck?[/b] // Übergabe an Extern if Assigned(FOnCommand) then FOnCommand(Self, AUser, Command, Framelist); end; end; Framelist.Free; end; procedure TDC_SPA.HandleLogin(AClient: TClient; FrameList: TFrameList); var Index: Integer; AUser: TUser; AuthVal: Boolean; begin if Framelist.Count <> 6 then // Anzahl der Frames MUSS 6 sein begin SendMessage(AClient.Socket, CMD_LOGIN_FAIL, 'Login Error. Not enough parameters'); // Fehlermeldung falls ungültig AClient.Socket.Close; // Socket freigeben Exit; end; if Not Users.FindUser( FrameList.Frames[1].Frame, Index ) then begin AUser := FUsers.AddConnection(AClient.Socket); AUser.SID := AClient.SID; AUser.LoginTime := Now; AUser.LPStamp := TimeStamp; AUser.Address := FrameList.Frames[3].Frame; AUser.User := FrameList.Frames[1].Frame; AUser.Name := FrameList.Frames[2].Frame; AUser.Pass := Framelist.Frames[4].Frame; if Assigned(FAuthData) then FAuthData(Self, AUser, AuthVal) else AuthVal := True; AUser.Authed := AuthVal; if AuthVal then begin SendMessage(AUser.Socket, CMD_LOGIN_OK, 'Logged on'); SendUserlist(AUser, ucsLogin); if Assigned(FConnectionsStatus) then FConnectionsStatus(Self, FClients.Count, FUsers.Count); end else begin SendMessage(AUser.Socket, CMD_LOGIN_FAIL, 'Login Disabled'); AUser.Socket.Close; // Verbindung trennen end; end else begin SendMessage(AClient.Socket, CMD_USER_IN_USE, 'User [b]already[/b] connected'); // Benutzer bereits verbunden AClient.Socket.Close; // Verbindung trennen end; end; procedure TDC_SPA.FSocketClientDisconnect(Sender: TObject; Socket: TCustomWinSocket); var Index: Integer; TmpUser: TUser; SID: Integer; begin if FUsers.FindSocket(Socket, Index) then begin TmpUser := FUsers.User[Index]; SID := TmpUser.SID; TmpUser.Free; end; if FClients.FindSocket(Socket, Index) then begin FClients.Client[Index].SID := 0; // Nutze ich nun zur Prüfung ob der Client noch vorhanden ist, damit gehts ohne Fehler FClients.Client[Index].Free; // <-- Hier wird das Item in dem Fall der Inhalt aus AClient freigegeben [/b]// Client ist TCollectionItem? Übernimmt die Collection die Einträge und gibt sie somit frei? // Grundsätzlich solltest du hier aber nil dem ehemaligen Eintrag zuweisen nach dem Free. Damit müsstest // du aber auch entsprechend darauf achten, dass du beim Zugriff auf die Collection NIL Einträge bekommen // kannst. end; if Assigned(FConnectionsStatus) then FConnectionsStatus(Self, FClients.Count, FUsers.Count); // Clients über die veränderung benachrichtigen end; |
Re: Abfragen ob eine Variable oder die Referenz noch existie
Das Speicherleck habe ich übersehen, das ist wirklich schlimm, das wird direkt behoben, danke :)
Das allererste mit den Exits war nut zum testen, hatte anfangs Break aber da übergang er es, mit Exit aber ebenfalls, darum bin ich ja drauf gekommen das eben noch Reste des AClient da sein müssen. Die Procedure ist schon komplett umgeändert. Habe vor dem Free einfach die SID auf 0 gesetzt und darauf dann geprüft, ob das nun die sauberste Lösung ist glaube ich nicht aber immerhin konnte ich damit erstmal weiter arbeiten ohne eine Exception. Ja die Collection übernimmt im Hintergrund alles. Das mit dem FreeandNil werde ich mal ausprobieren, sofern es auf Anhieb nicht zu viele Änderungen sind. Was den gesamten Source angeht, so würde ich den wenn er mal fertig wird so oder so von dritten prüfen lassen, habe sicherlich noch überall kleine Mängel und Lecks drin, ganz zu schweigen von Optimierungen. |
Re: Abfragen ob eine Variable oder die Referenz noch existie
Zitat:
Zitat:
Wenn du die SID später vergleichen willst, dann muss die Instanz am Leben bleiben, welche die SID hält. Zitat:
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:00 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz