![]() |
TIdTCPServer / TIdTCPClient => Ping - Pong
Hi,
bei meiner Anwendung muss immer eine Verbindung mit dem Server bestehen. Habe das früher mit den Sockets gemacht, da hat es so funktioniert. Jetzt wo ich das mit den Indys mache und alles auf Threads basiert, weis ich nicht ob das immer noch so funktionieren würde. Das ist der Client Execute, gekürzt.
Delphi-Quellcode:
Und der Server -> OnRead
while not Terminated do begin
if not fClient.Connected then try fClient.Connect(1000); except end; //Ping senden if fClient.Connected then begin cmd := TCommandHandling.Create(CMDPing); try fClient.WriteLn(cmd.SendFrames); msg := fClient.ReadLn; //Antwort cmdPong except fClient.Disconnect; //Timeout, kein Pong bekommen. end; end; //Text empfangen if fClient.Connected then begin try try IsTimeout := false; msg := fClient.ReadLn; except IsTimeout := True; end; if not IsTimeout then begin cmd := TCommandHandling.Create(CMDNone); try cmd.SetFrames(msg); try if Assigned(fOnRead) then fOnRead(cmd); except //Fehler in OnRead abfangen end; finally FreeAndNil(cmd); end; end; finally fCS.Leave; end; end; sleep(100); end;
Delphi-Quellcode:
Soweit funktioniert der Test bei 2 Computer. Gibt es noch was wo drauf ich achten muss oder eventuell was ich besser machen kann.
AThread.Connection.ReadTimeout := 1000;
fCS.Enter; try try msg := AThread.Connection.ReadLn; except exit; end; finally fCS.Leave; end; cmd := TCommandHandling.Create(CMDPong); try cmd.SetFrames(msg); if cmd.GetCmd = CMDPing then AThread.Connection.WriteLn(cmd.SendFrames) //Pong senden else begin //rest weiter geben if Assigned(fOnRead) then fOnRead(AThread, cmd); end; finally FreeAndNil(cmd); end; Mfg |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Ok so wie ich es jetzt gemacht habe geht es nicht.
Habe im Client einfach per Timer text gesendet und im Server den Text einfach wieder zum Client zurück gesendet. Da kommt nur alle paar Sekunden was an, wenn überhaupt. Irgend wo habe ich da noch einen Fehler.... //Edit Nach einer Zeit friert der gesamte Client ein. Habe jetzt den Text am Client mal nicht in der Listbox angezeigt und so funktioniert es. So sehe ich nicht ob Text angekommen ist, müste schon, aber die Anwendung läuft weiter... So schwer bzw. anders kann es doch gar nicht sein.... |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Hi Jackie,
1. Wozu soll die CriticalSection im OnExecute des Server sein(hoffe Du meinst OnExecute, denn geschrieben hast Du OnRead) Deine var msg, solltest Du einfach lokal im OnExecute deklarieren. 2. Sollte Dir bewußt sein, das das OnExecute des Servers andauerd hintereinander aufgerufen wird(solange wie Client verbunden ist), so kann es auch mal passieren das DEin AThread.Connection.ReadLn; nichts(Lerrstring) zurück liefert, diesen Fall solltest Du abfangen und nicht Dein Event feuern. 3. Sollte es ein Kommando für das saubere Abmelden des Clients geben, z.B. Client sendet "QUIT", Server und Client trennen danach die Verbindung sauber. 4. Benutzt Du noch die 9er Version der Indys, das an sich ist kein Problem ich habe auch noch ein paar Projekte damit laufen, generell sollte man aber bei Neuentwicklungen jetzt auf die 10er Version setzen. Greetz Data |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Hi DataCool,
also.... Zitat:
Habe die Funktion nur OnRead genannt. msg ist local. Zitat:
Zitat:
Zitat:
Mfg |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
HI Jackie,
1. Zitat:
2. Zitat:
In Indy10 würde das dann so aussehen :
Delphi-Quellcode:
In Indy9 sollte der Code auch funktionieren Du must nur AConntext durch AThread ersetzen und das IOHandler in der Mitte weg lassen.
// Bis max. 2,5 Sekunden warten das Daten erfolgreich in den Buffer geschrieben wurden
AContext.Connection.IOHandler.CheckForDataOnSource(2500); // Prüfen, ob die Client Verbindung noch besteht, eventuell hat der Server beim CheckForDataOnSource festgestellt das die Verbindung weg ist if not AContext.Connection.Connected then exit; // Sind keine Daten im Buffer, dann raus if AContext.Connection.IOHandler.InputBufferIsEmpty then exit; // hier jetzt weiter mit ReadLN ... sind jetzt auf jeden Fall Daten zum Lesen da ! // ... 3. Ok, dann ist ja alles gut ;-) 4. Zur Umstellung von Indy9 auf Indy10 existieren hier einige Threads, das ganze ist je nach Delphi Version mit ein bisschen "Handarbeit" verbunden. Deshalb hängt es von der größere des Projekts und DEiner aktuellen Entwicklungsumgebung ab ob es jetzt wirklich ratsam ist auf Indy10 umzustellen, oder ob für Deine Belange Indy9 absolut ausreichend ist. Eine großere Änderung von Indy9 zu Indy10 ist, das nicht mehr jede Connection Ihren eigenen Thread hat, sondern das es einen "Thread-Pool" gibt, der freie Threads an die verschiedenen Clients verteilt. Greetz Data |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
ok bin schon dabei die 10er zu installieren, weil wenn ich das schon neu mache dann kann ich auch die 10 nehmen. Habe bei der Installation schon einige Probleme. Die Demos funktionieren nicht, es können eigenschaften nicht gefunden werden so wie ganze units, obwohl ich die alles gesetzt habe.
Habe es nach dieser Anleitung gemacht ![]() |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Hi,
da gibt es hier im Forum weitaus genauere Anleitungen, ganz entscheided für die Sache ist allerdings, welche Delphi-Version Du benutzt ?! Und auch welche Indy-Version Du Dir gezogen hast ?! Die ist nämlich im Moment gespalten, empfehle Dir den "Tiburon-Branch" empfehlen. Greetz Data |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Habe Delphi 2007 Enterprise.
Oh, da gibt es auch noch mehrere Versionen. Von wo bekomme ich die? |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Hi,
schau mal ![]() Greetz Data P.S.: Bei Delphi2007 sollten eigentlich die Indy in einer frühen Version der 10er(10.1.5 oder 10.2.3) mit dabei sein, bin mir eigentlich ziemlich sicher, frage mich wie Du zu Indy9 kommst. |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Hi,
danke für den Link. Ist die Reihenfolge jetzt anders bei der Installation wie oben in der Anleitung?:stupid: Gute frage, ich weis es nicht... //Edit Habe das ganze jetzt wie folgt installiert Zitat:
Fehler, datei IdCoreGlobal nicht gefunden.... |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Hi,
ich denke Du must noch in Delphi unter "Tools\Optionen" den Bibliotheks-/Suchpfad setzen. Greetz Data |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Ne die Datei gibt es ja nicht bei mir auf dem Computer, habe ja danach gesucht.
Mein Projekt scheint aber noch zu funktionieren. Muste eigentlich nichts umstellen. Hoffe das ich das jetzt richtig installiert habe. Danke für deine Hilfe. Werde mal schauen wie weit ich komme... {Edit} Der Client friert dennoch ein :(, zum ko....{/Edit} {Edit} Wenn ich am Client das CS rausnehme kein Problem, irgend wo habe ich noch ein kleine Problem, naja....{/Edit} Mfg |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Hi Jackie,
dann poste nochmal Deinen jetzt aktuellen Code, Indy arbeitet übrings mit Blocking-Sockets, deshalb solltest Du Deinen "Client-Code" in einen Thread auslagern oder zumindest ein TIdAntiFreeze auf Deine Main-Form ziehen und die Eigenschaft "ApplicationHasPriority" auf true setzen. Greetz Data |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
hi,
ok wenn das nicht zu viel ist, mache ich das gerne. Ist alles im Thread :D Client Send
Delphi-Quellcode:
Client Execute
if not fclient.Connected then exit;
// fcs.Enter; try try fClient.WriteLn(ACmd.SendFrames); except end; finally // fcs.Leave; end;
Delphi-Quellcode:
fClient := TIdTCPClient.Create(nil);
fClient.ReadTimeout := 500; fClient.Host := fHost; fClient.Port := FPort; while not Terminated do begin //Prüfen ob Client Online if not fClient.Connected then begin try fClient.Connect(500); except //beep; end; end; //Ping senden (* if fClient.Connected then begin cmd := TCommandHandling.Create(CMDPing); try fCS.Enter; try fClient.WriteLn(cmd.SendFrames); msg := ''; msg := fClient.ReadLn; finally fCS.Leave; end; if msg = '' then fClient.Disconnect; except fClient.Disconnect; end; end; *) //Text empfangen if fClient.Connected then begin // fCS.Enter; try try IsTimeout := true; msg := fClient.ReadLn; IsTimeout := false; except //Timeout IsTimeout := True; end; if not IsTimeout then begin cmd := TCommandHandling.Create(CMDNone); try cmd.SetFrames(msg); try if Assigned(fOnRead) then fOnRead(cmd); except //Fehler in OnRead abfangen end; finally FreeAndNil(cmd); end; end; finally // fCS.Leave; end; end; sleep(100); end; |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
So nach dem ich jetzt schon den ganzen Tag am test bin und einfach nicht weiter weis.... Möchte ich das ganze mal beschreiben, vielleicht mach ich im Ansatz was falsch.
Ziel des Projektes ist es ein einfachen Server / Client zubekommen der Text über das Netzwerk sendet, später noch mit SSL. Die Clients müssen überwacht werden und sobald eine Verbindung nicht stimmt, muss der Server die Verbindung trennen und der client die Verbindung neu aufbauen. Der Server / TIdTCPServer. - Der Server läuft in einem Thread. - Im Execute vom Thread werden die Vars erstellt und eine While not Terminated Schleife mit sleep(100). - Im OnExecute vom Server werden die Daten mit ReadLn und einem Timeout (500) gelesen. Wenn Daten da sind. Daten in Befehl umwandeln. Wenn Befehl Ping sende Pong zurück, wenn andere Daten an fOnRead weitergeben zum verarbeiten. - Es wird kein CriticalSection verwendet. - Methode OnTimeAlive, hier prüft der Server anhand einer Liste welche Clients online sind, wenn Client nicht auf Ping antwortet, Verbindung trennen. Der Client / TIdTCPClient - Der Client läuft als Thread. - Execute vom Thread: prüfen ob Client Online ist, wenn nicht anmelden. - Execute vom Thread: Daten da, wenn nein exit, wenn ja Daten weiter an fOnRead geben - Methode Send. Sendet Daten an Server. Erst ein Ping senden und auf ein Pong warten, wenn Pong ok, dann Daten senden, wenn nicht exit und Verbindung neu aufbauen. - Es wird kein CriticalSection verwendet. - Per Timer sendet der Client zum Test einen String zum Server. Soweit so gut, aber irgend wie komme ich noch wo durcheinander so das mein Client einfriert. (Noch ne frage, bei den Sockets habe ich die Befehle in einer Jobliste verarbeitet, heist wenn ein job nur halb gesendet wurde, wird gewartet bis dieser ganz da ist und erst dann weiter gegeben, wie ist das bei den Indys. Muss ich mich auch drum kümmern, wenn ein Befehl zu groß ist das dieser auch ganz ankommt? Glaube das mit den Indy Threads habe ich noch nicht ganz verstanden :( ) Mfg |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Hi Jackie,
der Source-Code im Posting davor lässt "leider" noch ganz klar darauf schliessen das Du Indy9 verwendest, was auch nicht schlimm ist, Dein Problem bekommst Du mit Indy9 oder Indy10 gelöst. Wie Du allerdings am besten von Indy9 auf Indy10 umstellst, kann Du ![]() Unabhängig davon nochmal zu Deinem Problem, wenn ich ein wenig Luft hätte würde ich Dir ja ne kleine Demo mit Client & Server schreiben. Allerdings ist ist bei mir im Moment alles andere mehr verfügbar als Zeit :roll: Nochmal zum vorgehen, der Client sollte wie von Dir auch schon genannt in einem eigenen Thread laufen. Der Server(egal ob Indy9/Indy10) behandelt alles intern schon in Threads, Du brauchst KEINE(N) extra Thread(s) erzeugen. DU DARFST AUF KEINEN FALL EINE SCHLEIFE INS ONEXECUTE DES SERVERS BAUEN ! Das OnExecute läuft selber schon in der Schleife eines Indy internen Threads, d.h. solange der Client connected ist tritt immer wieder das OnExecute ein !! Deine "Jobliste" brauchst Du bei Indy nicht, das behandeln die alles intern, ReadLn liefert erst Daten zurück wenn auch ein CRLF angekommen ist. Ich denke Dein Fehler liegt im Servercode, kannst Du denn nicht komplett posten ? Greetz Data |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Hi Data,
danke erst mal das du dir die Zeit nimmst das ganze mit mir durchzugehen. Eventuell noch als Hinweis. Die Befehle die versendet werden sehen so aus.
Delphi-Quellcode:
Denke werde es aber so machen wie ich hier im
TSocketPaket = record
//Header sizeGesamt : integer; sizeDaten : integer; Command : TCommand; //Daten daten : TStringlist; end; function TCommandHandling.SendFrames: String; var datastring, FFrames : string; size : integer; begin datastring := fSocketPaket.daten.CommaText; //4 = Integer / Geaamtlänge //4 = Integer / Befehl //4 = Integer / Länge Daten // = 12 SetLength(FFrames,12+Length(datastring)); ZeroMemory(Pchar(FFrames),Length(FFrames)); //1-4 -> gesamtlänge PCardinal(@FFrames[1])^ := Length(fframes); //gesamtlänge //5-8 -> befehl PCardinal(@FFrames[5])^ := Integer(fSocketPaket.Command); //9-12 -> länge daten PCardinal(@FFrames[9])^ := Length(datastring); //13-x -> daten size := length(datastring); if datastring <> '' then System.Move(Pchar(datastring)^,Pointer(@FFrames[13])^,Size); result := FFrames; end; ![]() Also so in der Art. Starte Kommunikation, warte auf antwort, sende Daten, warte auf Antwort, sende Daten, ...., beende Kommunikation. Warte auf Kommunikation Start... Das ist der Server.
Delphi-Quellcode:
Mfg
unit DTS_Server;
interface uses Windows, Classes, IdTCPServer, SysUtils, DTS_Command, DTS_Utils, IdSocketHandle, SyncObjs, Contnrs; Type TServerOnRead = Procedure(AThread: TIdPeerThread; Data : TCommandHandling) of object; TServerOnEvent = Procedure(AThread: TIdPeerThread) of object; TClientData = class(TObject) private fDNS : String; { Hostname } fConnected, { Time of connect } fLastAction : TDateTime; { Time of last transaction } fThread : Pointer; { Pointer to thread } public Property DNS : String read fDNS write FDNS; Property Connected : TDateTime read fConnected write fConnected; Property LastAction : TDateTime read fLastAction write fLastAction; Property Thread : Pointer read fThread write fThread; end; TDTSServer = class(TThread) private fPort : Integer; fClientList : TobjectList; fServer : TIdTCPServer; fOnRead : TServerOnRead; fOnDisconnect : TServerOnEvent; fBindIP : String; Procedure OnExecute(AThread: TIdPeerThread); Procedure OnConnect(AThread: TIdPeerThread); Procedure OnDisconnect(AThread: TIdPeerThread); public Constructor Create(Port : integer; BindIP : String = '127.0.0.1'); Destructor Destroy; override; Procedure Broadcast(Data : TCommandHandling); Property OnClientReadData : TServerOnRead read fOnRead write fOnRead; Property OnClientDisconnect : TServerOnEvent read fOnDisconnect write fOnDisconnect; protected Procedure Execute; override; Procedure DoTerminate; override; end; implementation { TDTSServer } procedure TDTSServer.Broadcast(Data: TCommandHandling); var i : integer; RecClient : TClientData; RecThread : TIdPeerThread; begin try for i := 0 to fClientList.Count-1 do // iterate through client-list begin RecClient := TClientData(fClientList.Items[i]); // get client-object RecThread := RecClient.Thread; // get client-thread out of it RecThread.Connection.WriteLn(Data.SendFrames); // send the stuff end; finally FreeAndNil(Data); end; end; constructor TDTSServer.Create(Port: integer; BindIP : String = '127.0.0.1'); begin inherited Create(false); fPort := Port; fBindIP := BindIP; end; destructor TDTSServer.Destroy; begin self.Terminate; self.WaitFor; inherited; end; procedure TDTSServer.DoTerminate; begin inherited; end; procedure TDTSServer.Execute; var MSG : TMsg; Binding : TIdSocketHandle; begin inherited; fClientList := TObjectList.Create; fServer := TIdTCPServer.Create(nil); // fServer.TerminateWaitTime := 3000; fServer.Bindings.Clear; Binding := fServer.Bindings.Add; Binding.IP := fBindIP; Binding.Port := fPort; fServer.OnExecute := OnExecute; fServer.OnConnect := OnConnect; fServer.OnDisconnect := OnDisconnect; fServer.Active := true; while not Terminated do begin sleep(100); end; // while (GetMessage(msg, 0, 0, 0) and not Terminated) do // DispatchMessage(msg); fServer.Active := false; FreeAndNil(fServer); FreeAndNil(fClientList); end; procedure TDTSServer.OnConnect(AThread: TIdPeerThread); var Data : TClientData; begin Data := TClientData.Create; Data.DNS := AThread.Connection.LocalName; Data.Connected := Now; Data.LastAction := Now; Data.Thread := AThread; AThread.Data := TClientData(Data); fClientList.Add(Data); end; procedure TDTSServer.OnDisconnect(AThread: TIdPeerThread); var Data : TClientData; begin if(Assigned(fOnDisconnect)) then fOnDisconnect(AThread); Data := TClientData(AThread.Data); fClientList.Remove(Data); AThread.Data := nil; end; procedure TDTSServer.OnExecute(AThread: TIdPeerThread); var msg : string; cmd : TCommandHandling; begin AThread.Connection.ReadTimeout := 1000; try msg := AThread.Connection.ReadLn; except exit; end; cmd := TCommandHandling.Create(CMDPong); try cmd.SetFrames(msg); if cmd.GetCmd = CMDPing then begin cmd.SetCommand(CMDPong); AThread.Connection.WriteLn(cmd.SendFrames); end else begin if Assigned(fOnRead) then //Weiter an die eigentliche Command behandlung. fOnRead(AThread, cmd); end; finally FreeAndNil(cmd); end; end; end. |
AW: TIdTCPServer / TIdTCPClient => Ping - Pong
Hi Jackie,
schonmal kurz vorab : Der Server darf/sollte nicht innerhalb eines TTHreads laufen, das war vielleicht bei Deinen Sockets erforderlich, aber bei Indy ist das so nicht gewollt, weil Indy intern selber alles in Threads handelt. Also leite Deine Klasse "TDTSServer" NICHT von TThread ab, sondern lass das ganze mal als einfache Klasse laufen. OnExecute und OnTerminate ersetzt Du dann mit Sart und Stop oder wie auch immer Du es brauchst. Greetz Data |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:49 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