![]() |
TIdTCPServer (Indy) und TClientSocket
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich stehe vor folgendem Problem: ich benötige einen TCP-Server, der auf einem Linux-System mit wine laufen kann. Das funktioniert offenbar mit den Indys. Ich habe breits ![]()
Delphi-Quellcode:
vom Server sende, kommen am Client auch an.
AContext.Connection.IOHandler.WriteLn('Willkommen');
Ich habe aber das Problem, dass es umgekehrt nicht klappt. Wenn ich also mit
Delphi-Quellcode:
etwas vom Client sende, kommt nichts beim Server an. Es wird noch nicht einmal das Ereignis
TClientSocket.Socket.SendText('Hello World');
Delphi-Quellcode:
ausgelöst.
TIdTCPServer.OnExecute(AContext: TIdContext);
Kann mir jemand erklären, woran das liegt? Falls ja, gibt es Abhilfemöglichkeiten? Den Quellcode habe ich angehängt. Es sind meine Anfänge mit den Indys und ich habe mitbekommen, dass es da diverse Unterschiede in den Versionen gibt, die zu Problemen führen. bei diesem Projekt benutze ich Delphi XE5. Gruß, Alex |
AW: TIdTCPServer (Indy) und TClientSocket
Hallo,
Firewall, seLinux. Alternativ kannst Du auf dem Server mal nc -l <Dein Port> starten und dann versuchen dich mit dem Client zu verbinden. Grüße Klaus |
AW: TIdTCPServer (Indy) und TClientSocket
Danke für die Antwort.
Zitat:
Aber daran liegt es nicht, weil dasselbe Problem auch auftritt, wenn ich das auf demselben oder anderen Windows-Rechnern mache. Es liegt also gar nicht an Linux... Zitat:
[EDIT] Ich hatte schon verschiedene Strings (Ansi, Wide, Short) im Verdacht. Aber das kann es nicht sein. Denn dann müsste zum einen ja das Ereignis zumindest ausgelöst werden und er müsste mir dann irgend welchen Datenmüll anzeigen. TClientSocket nutzt AnsiString und - wenn ich das richtig den Quellen entnommen habe - ist es bei den Indys auch AnsiString. Also theoretisch alles im grünen Bereich. [/EDIT] Gruß, Alex |
AW: TIdTCPServer (Indy) und TClientSocket
Offenbar hängt es schon an Delphi - oder meinen bescheidenen Programmierkünsten:
Ich habe mir zu Testzwecken die Mühe gemacht und auf einem Form "schnell" mal je Server und Client der Indys und einen TClientSocket platziert und mit Code unterlegt. Ich kann das auch anhängen, falls jemand Interesse hat. Der Indy-Client kann etwas an den Indy-Server senden - hätte mich auch gewundert, wenn es nicht so gewesen wäre. Mit dem TClientSocket kann ich mich immerhin noch zum TIdTCPServer verbinden. Aber wenn ich mit
Delphi-Quellcode:
etwas absetze, kommt das aus mir unerfindlichen Gründen nicht an - genau wie bei den getrennten Programmen. Das Ereignis wird auch hier nicht ausgelöst :evil:
ClientSocket.Socket.SendText('Hello World');
Jetzt wollte ich gern testen, ob es umgekehrt klappt, vom Server etwas an TClientSocket zu senden. Bedauerlicher Weise hängt sich folgender Code (den ich im www gefunden habe) ohne jedwede Fehlermeldung auf; selbst das Senden an den Indy-Client klappt somit nicht:
Delphi-Quellcode:
Kann mit dazu jemand etwas sagen?
Procedure TForm1.BtnBrdcastClick(Sender: TObject);
Var CList : TList; I : Integer; Begin CList:= IdTCPServer.Contexts.LockList; Try For I:= 0 To Pred(CList.Count) Do Try TIdContext(CList[I]).Connection.SendCmd(EDBrdCast.Text); Except End; Finally IdTCPServer.Contexts.UnlockList; End; End; Ich würde wirkllich gern den Indy-Server und den Delphi-Client miteinander verbinden. So schnell will ich da nicht aufgeben. Aber ich finde schon jetzt, dass die Indys vergleichsweise unhandlich sind und merkwürdig reagieren... Gruß, Alex |
AW: TIdTCPServer (Indy) und TClientSocket
Ich weiß nicht ob es richtig ist was ich jetzt sage, aber ich hatte so etwas auch mal testweise ausprobiert.
Beim Zugriff auf die LockList wird ein SperrFlag gesetzt welches mit UnlockList aufgehoben wird. Das Problem bei mir war allerdings, dann ich, egal ob ich mir die Instanz zwischengespeichert habe oder nicht, pro Zugriff auf die LockList ein UnlockList aufrufen musste. Erst dann hat es funktioniert. Aber ich dachte mir damals schon, dass das nicht richtig sein kann. Eventuell findet sich ja jemand der das schon gemacht hat. Stahli hat doch aktuell so ein Socket Framework gebaut wenn ich mich recht erinnere. Ob das allerdings etwas damit zu tun hat weiß ich nicht. |
AW: TIdTCPServer (Indy) und TClientSocket
|
AW: TIdTCPServer (Indy) und TClientSocket
Dank des Quellcodes in C++ (?) von Bambini habe ich es geschafft:
Delphi-Quellcode:
Einen Fehler ("Items[I]" statt nur "[I]") und eine Unwissenheit (
Procedure TForm1.BtnBrdcastClick(Sender: TObject);
Var CList : TList; I : Integer; Begin CList:= IdTCPServer.Contexts.LockList; Try For I:= 0 To Pred(CList.Count) Do Try TIdContext(CList.Items[I]).Connection.IOHandler.WriteLn(EDBrdCast.Text); TIdContext(CList.Items[I]).Connection.IOHandler.WriteBufferFlush; Except End; Finally IdTCPServer.Contexts.UnlockList; End; End;
Delphi-Quellcode:
fehlte ganz) habe ich ausgemerzt.
WriteBufferFlush
Besonders "lustig" ist nun, dass ich die Strings mittels Ereignis mit
Delphi-Quellcode:
erhalte. Empfangen funktioniert also, senden leider nicht - wie unpraktisch. Jetzt suche ich in
System.Win.ScktComp.TClientSocket
Delphi-Quellcode:
eine Möglichkeit, die Daten abzurufen. Die Ereignisse habe ich alle durchprobiert. Da tut sich leider nichts. Es ist so unschön, dass ich irgendwie kein Tutorial finde, in dem einmal die Kommunikation vollständig aufgezeigt wird.
IdTCPClient.TIdTCPClient
Ist es wirklich so, dass man die Daten "von Hand" über ein Polling auslesen muss? Ooch man! Gruß, Alex |
AW: TIdTCPServer (Indy) und TClientSocket
Ich hatte hier noch nichts beigetragen, weil ich nicht wusste, ob ich das Problem überhaupt richtig verstanden habe.
Da ich aber angesprochen wurde versuche ich mal was ins blaue... Indy funktioniert immer blockierend. Client fragt beim Server an und wartet auf Antwort. Der Server startet Threads für die Verarbeitung der Anfrage. Hierzu mal ein älterer Beitrag: ![]() Ich habe jetzt mal eine asynchrone Kommunikation getestet: ![]() Das funktioniert anscheinend richtig gut und ich bin dabei, mein echtes Projekt von Indy darauf umzustellen. Die Sockets funktionieren aber m.E. in dieser Form nur unter Windows. Falls das irgendwann doch Probleme macht, könnte ich dies auch wieder auf Indy oder etwas anderes umstellen, da Server und Clients im Grunde "Message-Objekte" austauschen, die mein Package automatisiert ordnet, zerlegt, überträgt, wieder herstellt und auf der Empfangsseite zur Verarbeitung bereitstellt. Ob die Übertragung dabei über Sockets oder Indy bzw. asynchron oder blockierend erfolgt ist dann eher nebensächlich. |
AW: TIdTCPServer (Indy) und TClientSocket
Liste der Anhänge anzeigen (Anzahl: 2)
Danke.
Ich hätte furchtbar gern die Sockets von Delphi genutzt. Aber ich habe das Problem, dass diese sich faktisch nicht aus der VCL lösen lassen und ich damit mit Linux/Wine scheitere. "Das funktioniert anscheinend richtig gut." kann ich nur bestätigten, nützt mir aber nichts :cry: Ich wollte deshalb wenigstens auf der Client-Seite bei den Sockets bleiben, damit ich nicht alles neu programmieren muss. Aber irgendwie kommt vom TClientSocket nichts beim TIdTCPServer an. Blockierend bedeutet, dass ich lesen kann, dann aber meine GUI hängt oder ich es in einen Thread auslagere, richtig? Ich habe mich für Letzteres entschieden und jetzt mal wieder Quellcode angehängt. Beteiligt an der Spielerei sind TClientSocket, TIdTCPClient und TIdTCPServer. Nach meinem beschränkten Verständnis sollte doch beim Senden vom Server wenigstens irgend etwas ankommen - also zumindest das Ereignis ausgelöst werden. Ich bin immer noch nicht dahiner gestiegen, warum das so ist :wall: [OT] Ein weiteres lustiges Phänomen ist auch, dass der TIdTCPServer offenbar ein Problem damit hat, die richtige Anzahl der verbundenen Clients zu liefern. Auch hierzu habe ich mich eines Codes aus dem www bedient, der jedoch merkwürdige Werte liefert. Aber dazu mache ich ggf. ein anderes Thema auf ... [/OT] |
AW: TIdTCPServer (Indy) und TClientSocket
Zitat:
Daher musst du auch ein "Satz" mit CR/LF schicken. Also noch ein +#13#10 dranhängen. |
AW: TIdTCPServer (Indy) und TClientSocket
Zitat:
Warum das so ist, verstehe ich trotzdem nicht so ganz.
Delphi-Quellcode:
sendet etwas ab, was z.B.
TClientSocket
Delphi-Quellcode:
auch ohne #13#10 empfangen würde. Dass ich mit
TServerSocket
Delphi-Quellcode:
auslese, ist korrekt. Aber das Ereignis
ReadLn();
Delphi-Quellcode:
wird nach meinem Verständnis ausgelöst, wenn Daten kommen.
OnExecute
Delphi-Quellcode:
weiß doch zu diesem Zeitpunkt noch gar nicht, wie ich was auslesen werde. Warum wird es ohne #13#10 nicht ausgelöst?
TIdTCPServer
Wenn mir jetzt noch jemand dieses - aus meiner Sicht - merkwürdige Verhalten erklären könnte, wäre das phönomenal. Danke aber auf jeden Fall an alle und insbes. Bambini - auf diese Lösung wäre ich nie gekommen! Gruß, Alex |
AW: TIdTCPServer (Indy) und TClientSocket
Zitat:
PS: Das OnExecute wird aus einem Thread aus gerufen, d.h. Zugriffe auf die UI (bei dir das TMemo) sind da gefährlich. Das sollte mit TThread.Synchronize(nil, ...) geschützt werden. |
AW: TIdTCPServer (Indy) und TClientSocket
Zitat:
Zitat:
Innerhalb eines Threads ist mir das klar. Da Du das weißt, hast Du vermutlich meinen Quellcode angeschaut. Dort habe ich die das Polling des
Delphi-Quellcode:
extra in einen Thread ausgelagert. Dann müsste ich ja eine eigene Klasse von
TIdTCPClient
Delphi-Quellcode:
reinbasteln. Das ist dann auch - gelinde gesagt - ungünstig, wenn man Objekte in die IDE integriert, ich als Laie denke, alles ist schick, und mir das dann um die Ohren fliegt ...
TIdTCPServer
Danke schon mal für den Hinweis. |
AW: TIdTCPServer (Indy) und TClientSocket
Zitat:
Zitat:
Delphi-Quellcode:
Procedure TForm1.IdTCPServerExecute(AContext: TIdContext);
Var Data:String; Begin Data:= AContext.Connection.Socket.ReadLn(); Data:= Trim(Data); TThread.Synchronize(nil, procedure() begin ScrollLog('[Srv]: received:'); ScrollLog('=> ' + Data); end); Zitat:
Zitat:
|
AW: TIdTCPServer (Indy) und TClientSocket
Danke nochmal für's Drüberschauen und die Erklärung.
Zitat:
Ich vermisse dann auch einen Compiler-Hinweis. Der "liest" ja den Code und sollte das wissen :lol: Ich habe in meinem Thread das Ereignis aus dem Thread heraus threadsicher (hoffe ich) aufgerufen. Warum machen das die Indys nicht gleich so? Und was mache ich, wenn die Prozeduren größer als eine klitzekleine Ausgabe in der GUI werden? ... Zitat:
Delphi-Quellcode:
In diesem Fall muss ich dann innerhalb des VCL-Teils kein Syncronize mehr benutzen, oder doch?
// Völlig ungetestet zusammengeschrieben, um die Frage zu verdeutlichen!!!
type TfoobarEvent = procedure (Value: Integer) of object; foobar = class(TThread) private FValue : Integer; FOnErgebnis : TfoobarEvent Procedure FireThreadSafe; protected procedure Execute; override; public property OnErgebnis: TfoobarEvent read FOnErgebnis write FOnErgebnis; end; implementation procedure foobar.FireThreadSafe; Begin if Assigned(FOnErgebnis) then FOnErgebnis(FValue); End; procedure foobar.Execute; begin while not Terminated do begin FValue:= Random(5000); if (FValue = 0) then Synchronize(FireThreadSafe); end; end; Ich bin jetzt etwas verwirrt. |
AW: TIdTCPServer (Indy) und TClientSocket
Zitat:
Zitat:
Daher ist es schon sehr gut, dass die für jeden Client im eigenen Thread läuft. Zitat:
|
AW: TIdTCPServer (Indy) und TClientSocket
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Kannst Du mir bitte einen Gefallen tun: Du schriebst weiter oben, dass bei Dir das Ereignis auch ohne #13#10 ausgelöst wird. Bei mir eben nicht. Am Quellcode kann es also (theoretisch) nicht liegen. Macht es Dir was aus, mit ggf. per PN oder so eine von Dir compilierte exe-Datei zuzusenden? Gruß, Alex |
AW: TIdTCPServer (Indy) und TClientSocket
Zitat:
Von "Außen" sieht man das nicht. Nur wenn du einen BreakPoint in das OnExecute beim begin setzt, also VOR dem ReadLn() und deinen String ohne CRLF schickt, solltest du es auch sehen. |
AW: TIdTCPServer (Indy) und TClientSocket
Zitat:
|
AW: TIdTCPServer (Indy) und TClientSocket
Zitat:
Delphi-Quellcode:
wird aufgerufen. Warum sehe ich dann wiederum keine Meldung; auch wenn ich die Ausgabe ganz an den Anfgang setze:
OnExecute
Delphi-Quellcode:
Procedure TForm1.IdTCPServerExecute(AContext: TIdContext);
Var Data:String; Begin ScrollLog('OnExecute();'); Application.ProcessMessages; Data:= AContext.Connection.Socket.ReadLn(); Data:= Trim(Data); // Sonder- und Leerzeichen entfernen TThread.Synchronize(nil, // threadsicherer VCL-Zugriff Procedure() Begin ScrollLog('[Srv]: received:'); ScrollLog('=> ' + Data); End); End; |
AW: TIdTCPServer (Indy) und TClientSocket
Zitat:
Und das macht jeder Thread pro Connection, egal ob da etwas auf der Leitung angekommen ist oder nicht. Mit ReadLn legst du den schlafen, bis ReadLn etwas zurück liefert. PS: mit
Delphi-Quellcode:
kannst abfragen, ob da etwas zum lesen gibt.
if AContext.Connection.Socket.Readable() then begin
|
AW: TIdTCPServer (Indy) und TClientSocket
Ich denke (hoffe), dass folgendes zutrifft:
TForm1.IdTCPServerExecute(...) ist eine Ereignisbehandlung. TForm1.KeyPress(...) auch. KeyPress wird vom Mainthread selbst ausgelöst, wenn von Windows eine Message TasteGedrückt ansteht. KeyPress läuft also innerhalb des Mainthreads und ist somit (Main-)Threadsafe. IdTCPServerExecute wird jedoch von einem aus Indy erzeugten Thread heraus aufgerufen - also nicht aus dem Mainthread heraus. Wenn dort irgendwelche Schweinereien gemacht werden, die den Mainthread bzw. das Formular berühren, dann kann das zu Problemen führen. Innerhalb eines Thread-Kontextes sollte man nie Application.ProcessMessages und nie ShowMessages o.ä. aufrufen. Aufrufe, die den Mainthread berühren müssen über Synchronize aufgerufen werden, damit es keine Zugriffskonflikte mit dem Mainthread gibt. 2 Threads, die da weiterhelfen können: ![]() ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:47 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