![]() |
IdTCPServer Threadproblem
Hallo zusammen,
ich bin gerade dabei eine Client->Server->Client Anwendung zuschreiben. Mein großes Problem ist dabei, sobald ein Client sich einmal mit dem Server verbunden hat und dann wieder disconnected und ich den Server beenden möchte, dass diese Serveranwendung einfriert und ich diese nur noch über den Taskmanager beenden kann. Meine Einzige Vermutung liegt nun darin, dass die ThreadConnections nicht ordentlich geschlossen werden. Anbei mal die wichtigsten Codesnippets aus meinem Projekt:
Delphi-Quellcode:
Ich bin bereits seit Tagen auf der Suche nach einer Lösung. Ich hoffe ihr könnt mir weiterhelfen.
type
PClient = ^TClient; TClient = record // Objekt enthält Daten vom Client IP : String[15]; { IP Adressse des Users } UserID : String[10]; { Benutzer ID in der DB } UserName : String[100]; { Benutzername } Connected : TDateTime; { Zeitstempel des Verbindungsaufbaus } Thread : Pointer; { Pointer zum IdContext-Thread } end; . . . var frmMain : TfrmMain; Clients : TThreadList; . . . procedure TfrmMain.TCPServerConnect(AContext: TIdContext); var NewClient: PClient; begin GetMem(NewClient, SizeOf(TClient)); NewClient.IP := AContext.Connection.Socket.Binding.PeerIP; NewClient.Connected := Now; NewClient.Thread := AContext; AContext.Data:=TObject(NewClient); try Clients.LockList.Add(NewClient); finally Clients.UnlockList; end; end; procedure TfrmMain.TCPServerDisconnect(AContext: TIdContext); var ActClient: PClient; vI : Integer; begin ActClient := PClient(AContext.Data); try Clients.LockList.Remove(ActClient); for vI:=0 to lvConnectedClients.Items.Count-1 do if(PClient(lvConnectedClients.Items[vI].Data)^.IP = ActClient.IP) then begin Dispose(lvConnectedClients.Items[vI].Data); lvConnectedClients.Items[vI].Delete; end; grpConnectedClients.Caption := 'Angemeldete Clients (' + IntToStr(lvConnectedClients.Items.Count) + ' Benutzer)'; finally Clients.UnlockList; end; FreeMem(ActClient); AContext.Data := nil; end; procedure TfrmMain.TCPServerExecute(AContext: TIdContext); var Data: String; vI: Integer; ActClient : PClient; begin Data := AContext.Connection.Socket.ReadLn; Data := decodeStr(Data); ActClient := PClient(AContext.Data); if(Pos('[CMClient]AuthMe', Data) > 0) then begin addToLog('Authentifizierungsanfrage von: ' + AContext.Binding.PeerIP, 0, [], 8); doSELECT('SELECT usr_id, usr_loginName FROM cm_user WHERE usr_loginName = "' + GetTagData('Username', Data) + '" AND usr_loginPassword = "' + GetTagData('Password', Data) + '" LIMIT 1'); if(Query.RecordCount <> 0) then begin addToLog('Authentifizierung erfolgreich.', 15, [], 8, clGreen); ActClient.UserID := Query.FieldByName('usr_id').AsString; ActClient.UserName:= Query.FieldByName('usr_loginName').AsString; lvConnectedClients.AddItem(Query.FieldByName('usr_loginName').AsString, Pointer(ActClient)); lvConnectedClients.Items[lvConnectedClients.Items.Count-1].SubItems.Add(''); AContext.Connection.Socket.WriteLn(encodeStr('[CMServer]Verify<Reason>Success</Reason>')); end else begin addToLog('Authentifizierung fehlgeschlagen.', 15, [], 8, clRed); AContext.Connection.Socket.WriteLn(encodeStr('[CMServer]Verify<Reason>Failed</Reason><ErrorMsg>Falsche Benutzer/Passwort Kombination!</ErrorMsg>')); end; exit; end; end; Vielen Dank schon einmal im voraus. Viele Grüße Nakaron |
Re: IdTCPServer Threadproblem
Hi Nakaron,
ich konnte leider beim ersten drüber schauen keinen Fehler finden. Allerdings kann ich Dir sagen das ich bei Delphi 2007 + Indy10 NICHT diese Probleme habe. Bei mir sieht die Struktur zwar etwas anders aus, aber vom Prinzip genau der gleiche Ablauf, nur das ich die Verification des Clients schon im OnConnect Ereignis behandle und nur ein TClient Object erzeuge wenn die Anmeldung/verifizierung erfolgreich war. Bei Deiner Lösung wird ja bei jedem Port-Scan ein Client Object erzeugt ... Ich schaue nachher aber nochmal genauer über Deinen Code, *Edit* Denke habe die Ursache gefunden, Dein Client schickt nie ein "Disconnect/QUIT" Commando zum Server ! Somit kann der Server gar nicht feststellen, wann der Client sich disconnecten will. Mache bitte mal folgendes : - Dein ganzes Handling für die Client-Verifizierung bitte in das OnConnect ! - Wenn beim OnConnect kein gültiges Login gesendet wird, die Connection sofort wieder schliessen - Erst nach erfolgreicher Anmeldung TClient erzeugen und in .Data ablegen - Im OnExecute nut Commandos behandeln die nach dem Login erfolgen, aber dort muss es auf jeden Fall ein Kommando wie z.B. "QUIT" geben, wenn der SErver dieses Commando vom Client erhält muss er die Connection schliessen - Im OnDisconnect musst Du prüfen, ob im .Data Daten vorhanden sind If Assigned(....Data) then begin - ansonsten .Data = nil war es nur ein Port-Scan Greetz DataCool |
Re: IdTCPServer Threadproblem
Hi DataCool,
danke erstmal für deine schnelle Antwort. Die Clientverifizierung kann ich leider nicht in das OnConnect packen, da der Client erst nach dem Connect die vom Clientbenutzer eingegebenen Logindaten an den Server sendet. Beim Server wird dann im OnExecute geprüft ob die Logindaten mit denen, welche sich in einer MySQL Datenbank befinden, übereinstimmen. Viele Grüße Nakaron |
Re: IdTCPServer Threadproblem
Hi,
Zitat:
Du kannst im OnConnect des Servers auch ein ReadLn machen ;-) Greetz DAtaCool |
Re: IdTCPServer Threadproblem
Ok, daran hab ich nicht gedacht ;)
Hab nun alles eingebaut was du mir geraten hast. Eine Frage habe ich dennoch: Was ist, wenn die Verbindung vom Client einfach abbricht? Dann habe ich doch wieder das selbe Problem ... Viele Grüße Nakaron |
Re: IdTCPServer Threadproblem
Hi,
das löse ich immer so, indem ich dem Client Object eine Eigenschaft "LastAction" TDateTime gebe. Diese immer aktualisieren wenn was im OnExecute vom Client kommt. Dann machst Du Dir einen seperaten Timer oder Thread(eleganter) der in einem bestimmten Intervall alle Client objekte durchgeht schaut wann die letzte Action war und wenn diese zu lange her ist, dann versuchst Du in the Connection des Clients ein z.B. "NOOP" zu schreiben. Wenn der Client mittlerweile disconnected ist, dann merkt das jetzt auch der Server ;-) Wenn der Client noch verbunden ist, passiert nichts ausser das beim Client ein "NOOP" ankommt, das sollte natürlich gehandelt werden. Greetz DAtaCool |
Re: IdTCPServer Threadproblem
Vielen Dank DataCool. Du hast mir sehr geholfen.
Das Problem ist nun endlich gefixt. Bin dir echt was Schuldig ;) Viele Grüße Nakaron |
Re: IdTCPServer Threadproblem
Hi,
kein Problem, Indy ist mein Spezial Gebiet ;-) Werd bestimmt mal die ein oder andere Frage in nem anderem Bereich haben ;-) Bis dahin frohes Schaffen, Greetz DataCool |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:44 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-2025 by Thomas Breitkreuz