Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   TIdTCPServer (Indy) und TClientSocket (https://www.delphipraxis.net/190871-tidtcpserver-indy-und-tclientsocket.html)

Schwedenbitter 15. Nov 2016 15:12

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 diesen Code gefunden, der fast funktioniert. Ich kann eine Verbindung herstellen zwischen dem Server-Programm und dem TClientSocket herstellen. Und Daten, die ich mit
Delphi-Quellcode:
AContext.Connection.IOHandler.WriteLn('Willkommen');
vom Server sende, kommen am Client auch an.

Ich habe aber das Problem, dass es umgekehrt nicht klappt. Wenn ich also mit
Delphi-Quellcode:
TClientSocket.Socket.SendText('Hello World');
etwas vom Client sende, kommt nichts beim Server an. Es wird noch nicht einmal das Ereignis
Delphi-Quellcode:
TIdTCPServer.OnExecute(AContext: TIdContext);
ausgelöst.

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

Klaus01 15. Nov 2016 15:21

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

Schwedenbitter 15. Nov 2016 15:56

AW: TIdTCPServer (Indy) und TClientSocket
 
Danke für die Antwort.
Zitat:

Zitat von Klaus01 (Beitrag 1353749)
Firewall, seLinux.

Das ist immer das erste, was ich bei Tests mit dem Netzwerk deaktiviere, um "Irritationen" zu vermeiden :-D
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:

Zitat von Klaus01 (Beitrag 1353749)
Alternativ kannst Du auf dem Server mal nc -l <Dein Port> starten
und dann versuchen dich mit dem Client zu verbinden.

Siehe oben. Aber ich werde es mir merken, wenn es mal unter Windows läuft und es dann Probleme unter Linux geben sollte.

[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

Schwedenbitter 16. Nov 2016 13:06

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:
ClientSocket.Socket.SendText('Hello World');
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:

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:
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;
Kann mit dazu jemand etwas sagen?

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

Aviator 16. Nov 2016 15:22

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.

Bambini 16. Nov 2016 15:45

AW: TIdTCPServer (Indy) und TClientSocket
 
http://stackoverflow.com/questions/3...texts-locklist

Schwedenbitter 16. Nov 2016 19:15

AW: TIdTCPServer (Indy) und TClientSocket
 
Dank des Quellcodes in C++ (?) von Bambini habe ich es geschafft:
Delphi-Quellcode:
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;
Einen Fehler ("Items[I]" statt nur "[I]") und eine Unwissenheit (
Delphi-Quellcode:
WriteBufferFlush
fehlte ganz) habe ich ausgemerzt.

Besonders "lustig" ist nun, dass ich die Strings mittels Ereignis mit
Delphi-Quellcode:
System.Win.ScktComp.TClientSocket
erhalte. Empfangen funktioniert also, senden leider nicht - wie unpraktisch. Jetzt suche ich in
Delphi-Quellcode:
IdTCPClient.TIdTCPClient
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.

Ist es wirklich so, dass man die Daten "von Hand" über ein Polling auslesen muss? Ooch man!

Gruß, Alex

stahli 16. Nov 2016 20:12

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:
http://www.delphipraxis.net/171226-i...o-clients.html



Ich habe jetzt mal eine asynchrone Kommunikation getestet:
http://www.delphipraxis.net/190482-s...ockettest.html

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.

Schwedenbitter 16. Nov 2016 21:10

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]

Bambini 17. Nov 2016 08:19

AW: TIdTCPServer (Indy) und TClientSocket
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1353904)
Aber irgendwie kommt vom TClientSocket nichts beim TIdTCPServer an.

Du machst in deinem IdTCPServerExecute auf Server Seite ein ReadLn().
Daher musst du auch ein "Satz" mit CR/LF schicken. Also noch ein +#13#10 dranhängen.

Schwedenbitter 17. Nov 2016 09:38

AW: TIdTCPServer (Indy) und TClientSocket
 
Zitat:

Zitat von Bambini (Beitrag 1353943)
Daher musst du auch ein "Satz" mit CR/LF schicken. Also noch ein +#13#10 dranhängen.

Volltreffer! Tausend Dank.
Warum das so ist, verstehe ich trotzdem nicht so ganz.
Delphi-Quellcode:
TClientSocket
sendet etwas ab, was z.B.
Delphi-Quellcode:
TServerSocket
auch ohne #13#10 empfangen würde. Dass ich mit
Delphi-Quellcode:
ReadLn();
auslese, ist korrekt. Aber das Ereignis
Delphi-Quellcode:
OnExecute
wird nach meinem Verständnis ausgelöst, wenn Daten kommen.
Delphi-Quellcode:
TIdTCPServer
weiß doch zu diesem Zeitpunkt noch gar nicht, wie ich was auslesen werde. Warum wird es ohne #13#10 nicht ausgelöst?
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

Bambini 17. Nov 2016 09:51

AW: TIdTCPServer (Indy) und TClientSocket
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1353955)
Aber das Ereignis
Delphi-Quellcode:
OnExecute
wird nach meinem Verständnis ausgelöst, wenn Daten kommen.
Delphi-Quellcode:
TIdTCPServer
weiß doch zu diesem Zeitpunkt noch gar nicht, wie ich was auslesen werde. Warum wird es ohne #13#10 nicht ausgelöst?

Das OnExecute wird ja ausgelöst, nur der darin ausgeführte AContext.Connection.Socket.ReadLn(); wartet auf ein CR/LF.

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.

Schwedenbitter 17. Nov 2016 10:18

AW: TIdTCPServer (Indy) und TClientSocket
 
Zitat:

Zitat von Bambini (Beitrag 1353957)
Das OnExecute wird ja ausgelöst, nur der darin ausgeführte AContext.Connection.Socket.ReadLn(); wartet auf ein CR/LF.

Nein, leider nicht. Ich habe es eben nochmals ausprobiert, indem ich #13#10 wieder auskommentiert habe. OnExecute wird nicht abgefeuert.

Zitat:

Zitat von Bambini (Beitrag 1353957)
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.

Wie geht denn das?
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:
TIdTCPClient
extra in einen Thread ausgelagert. Dann müsste ich ja eine eigene Klasse von
Delphi-Quellcode:
TIdTCPServer
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 ...
Danke schon mal für den Hinweis.

Bambini 17. Nov 2016 10:30

AW: TIdTCPServer (Indy) und TClientSocket
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1353965)
Zitat:

Zitat von Bambini (Beitrag 1353957)
Das OnExecute wird ja ausgelöst, nur der darin ausgeführte AContext.Connection.Socket.ReadLn(); wartet auf ein CR/LF.

Nein, leider nicht. Ich habe es eben nochmals ausprobiert, indem ich #13#10 wieder auskommentiert habe. OnExecute wird nicht abgefeuert.

hm, bei mir schon. :gruebel:

Zitat:

Zitat von Schwedenbitter (Beitrag 1353965)
Wie geht denn das?

Dein Code sollte so aussehen:
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 von Schwedenbitter (Beitrag 1353965)
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:
TIdTCPClient
extra in einen Thread ausgelagert.

Passt.
Zitat:

Zitat von Schwedenbitter (Beitrag 1353965)
Dann müsste ich ja eine eigene Klasse von
Delphi-Quellcode:
TIdTCPServer
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 ...
Danke schon mal für den Hinweis.

Ich will nur sagen, dass das OnExecute() from TidTCPIPServer von einem Thread aus gerufen wird. Das macht die Komponente schon ganz alleine. Jedoch muss man dann aufpassen, das deine Code dann Threadsicher ist. D.h. Zugriffe auf Globale Variablen und UI sind zu synchronisieren (s.o.)

Schwedenbitter 17. Nov 2016 11:32

AW: TIdTCPServer (Indy) und TClientSocket
 
Danke nochmal für's Drüberschauen und die Erklärung.

Zitat:

Zitat von Bambini (Beitrag 1353967)
...
Dein Code sollte so aussehen: ...

Das isz jetzt zwar OT: aber wenn ich das richtig deute, muss ich dann auch VCL-Zugriffe in allen TIdTCPServer-Ereignissen entsprechend absichern? Das ist ein ganz schöner Overhead, finde ich.
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:

Zitat von Bambini (Beitrag 1353967)
Ich will nur sagen, dass das OnExecute() from TidTCPIPServer von einem Thread aus gerufen wird. Das macht die Komponente schon ganz alleine. Jedoch muss man dann aufpassen, das deine Code dann Threadsicher ist. D.h. Zugriffe auf Globale Variablen und UI sind zu synchronisieren (s.o.)

Aber dass das Ereignis aus einem Thread aufgerufen wird, macht es doch nicht automatisch threadunsicher, wenn es sauber programmiert wurde. Ich dachte immer, so wäre es richtig und alle schlauen Ersteller von Komponenten würden das so (richtig) machen:
Delphi-Quellcode:
// 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;
In diesem Fall muss ich dann innerhalb des VCL-Teils kein Syncronize mehr benutzen, oder doch?
Ich bin jetzt etwas verwirrt.

Bambini 17. Nov 2016 11:49

AW: TIdTCPServer (Indy) und TClientSocket
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1353986)
Das isz jetzt zwar OT: aber wenn ich das richtig deute, muss ich dann auch VCL-Zugriffe in allen TIdTCPServer-Ereignissen entsprechend absichern? Das ist ein ganz schöner Overhead, finde ich.
Ich vermisse dann auch einen Compiler-Hinweis. Der "liest" ja den Code und sollte das wissen :lol:

Wer welchen Code zur Laufzeit aufruft, kann der Compiler nicht sehen und daher nicht helfen.
Zitat:

Zitat von Schwedenbitter (Beitrag 1353986)
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? ...

Das bremst die Clients nebeneinander aus. Wenn Client1 in OnExecute() einen größeren Job zu erledigen hat, dann kann kein weiterer Client etwas machen.
Daher ist es schon sehr gut, dass die für jeden Client im eigenen Thread läuft.
Zitat:

Zitat von Schwedenbitter (Beitrag 1353986)
Zitat:

Zitat von Bambini (Beitrag 1353967)
Ich will nur sagen, dass das OnExecute() from TidTCPIPServer von einem Thread aus gerufen wird. Das macht die Komponente schon ganz alleine. Jedoch muss man dann aufpassen, das deine Code dann Threadsicher ist. D.h. Zugriffe auf Globale Variablen und UI sind zu synchronisieren (s.o.)

Aber dass das Ereignis aus einem Thread aufgerufen wird, macht es doch nicht automatisch threadunsicher, wenn es sauber programmiert wurde. Ich dachte immer, so wäre es richtig und alle schlauen Ersteller von Komponenten würden das so (richtig) machen:
Delphi-Quellcode:
// 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;
In diesem Fall muss ich dann innerhalb des VCL-Teils kein Syncronize mehr benutzen, oder doch?
Ich bin jetzt etwas verwirrt.

Nein muss du dann nicht mehr. Einmal Synchronize reicht.

Schwedenbitter 17. Nov 2016 12:34

AW: TIdTCPServer (Indy) und TClientSocket
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Bambini (Beitrag 1353996)
Wer welchen Code zur Laufzeit aufruft, kann der Compiler nicht sehen und daher nicht helfen.

Das ist richtig. Aber wenn ich z.B. einem String einen AnsiString zuweise oder umgekehrt, bekomme ich ja auch wenigstens eine Warnung - unabhängig davon, dass er das "durchcompiliert". Aber das führt auch zu weit.

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

Bambini 17. Nov 2016 13:36

AW: TIdTCPServer (Indy) und TClientSocket
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1354001)
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?

An einer EXE wirst du es aber nicht sehen können. Das OnExecute() wird zwar gerufen, aber an dem ReadLn() kommt er nicht vorbei.
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.

Bambini 17. Nov 2016 13:40

AW: TIdTCPServer (Indy) und TClientSocket
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1354001)
Das ist richtig. Aber wenn ich z.B. einem String einen AnsiString zuweise oder umgekehrt, bekomme ich ja auch wenigstens eine Warnung - unabhängig davon, dass er das "durchcompiliert". Aber das führt auch zu weit.

Der "Code" ist problemlos, der parallele Zugriff ist die Kunst dabei. Und Windows Controls, wie z.B. das TMemo, nehmen es einem recht schnell übel, wenn ein anderer Thread sich mit denen unterhalten will.

Schwedenbitter 17. Nov 2016 13:52

AW: TIdTCPServer (Indy) und TClientSocket
 
Zitat:

Zitat von Bambini (Beitrag 1354021)
An einer EXE wirst du es aber nicht sehen können. Das OnExecute() wird zwar gerufen, aber an dem ReadLn() kommt er nicht vorbei.
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.

Entschuldige bitte. Ich weiß, dass ich langsam wohl nerve. Aber ich muss nochmal fragen.
Delphi-Quellcode:
OnExecute
wird aufgerufen. Warum sehe ich dann wiederum keine Meldung; auch wenn ich die Ausgabe ganz an den Anfgang setze:
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;

Bambini 17. Nov 2016 14:25

AW: TIdTCPServer (Indy) und TClientSocket
 
Zitat:

Zitat von Schwedenbitter (Beitrag 1354025)
Aber ich muss nochmal fragen.
Delphi-Quellcode:
OnExecute
wird aufgerufen. Warum sehe ich dann wiederum keine Meldung; auch wenn ich die Ausgabe ganz an den Anfgang setze:
Delphi-Quellcode:
Procedure TForm1.IdTCPServerExecute(AContext: TIdContext);
Var
   Data:String;
Begin
   ScrollLog('OnExecute();');
   Application.ProcessMessages;

   Data:= AContext.Connection.Socket.ReadLn(); //<--- Das wartet ewig, bis da etwas kommt
   Data:= Trim(Data);   // Sonder- und Leerzeichen entfernen
   TThread.Synchronize(nil,   // threadsicherer VCL-Zugriff
      Procedure()
      Begin
         ScrollLog('[Srv]: received:');
         ScrollLog('=> ' + Data);
      End);
End;

Das OnExecute() wird von jedem IndyThread gerufen und zwar alle Nase lang, wenn du da nix machst, kommt der sofort wieder.
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:
 if AContext.Connection.Socket.Readable() then begin
kannst abfragen, ob da etwas zum lesen gibt.

stahli 17. Nov 2016 14:30

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:
http://www.delphipraxis.net/190294-p...alsection.html
http://www.delphipraxis.net/190675-c...mziehen-2.html


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:08 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz