Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Daten abholen bei TCPClient (https://www.delphipraxis.net/216462-daten-abholen-bei-tcpclient.html)

Schuby 2. Jan 2025 10:06

Daten abholen bei TCPClient
 
Hallo, ich komme einfach nicht mehr weiter, über einen Timer kann
ich wunderschön meine Daten abholen. Da ich aber mehrere Strings
gesendet bekomme will ich warten bis alles da ist.

Über meine Procedure TForm1.ReadData; bekomme ich nichts ausgelesen.
Über Timer geht es, woran liegt das ?


mfg

Delphi-Quellcode:
{#######################################################}
{           Timer1  Interval 100                        }
{#######################################################}
procedure TForm1.Timer1Timer(Sender: TObject);
begin
    if not Form1.TCPClient.Connected = true then Exit;
    if Form1.TCPClient.IOHandler.InputBufferIsEmpty then Exit;
    rec_str:= Form1.TCPClient.IOHandler.ReadLn();
    edit10.Text:= edit10.Text + rec_str;
    Memo1.Lines.Add(rec_str);
end;

{#######################################################}
{           TCP auslesen                          }
{#######################################################}
Procedure TForm1.ReadData;
var StartTimeOut : Integer;
    tmp : String;
begin
  rec_str:= '';
  StartTimeOut := Gettickcount + 200; //200Ms bis zum ersten zeichen...
  while Gettickcount < StartTimeOut do
  begin
    if not Form1.TCPClient.IOHandler.InputBufferIsEmpty then
    begin
      tmp:= Form1.TCPClient.IOHandler.ReadLn();
      rec_str := rec_str + tmp;
      StartTimeOut := Gettickcount + 100; //100ms TimeOut erhöhung..
    end;
    application.processmessages; //Anti Freeze
  end;
  Memo1.Lines.Add(rec_str);
end;

TurboMagic 2. Jan 2025 10:53

AW: Daten abholen bei TCPClient
 
Hallo,

ich kenne dioe benutzte Komponente jetzt nicht, aber falls diese ein Event zum Abholen der
Daten bereitstellt wäre es sinnvoll dieses zu benutzen. EIn Timer dient dann nur noch der
Timeout Erkennung.

Application.ProcessMessages sollte man ja schließlich soweit möglich vermeiden.

Schuby 2. Jan 2025 11:15

AW: Daten abholen bei TCPClient
 
Es ist die IdTCPClient1 und ich kann nichts erkennen das diese
Komponente ein Event zum Abholen hat.

application.processmessages;
habe ich mal rausgenommen.



mfg

Klaus01 2. Jan 2025 13:23

AW: Daten abholen bei TCPClient
 
.. gutes neues Jahr.
Vielleicht ist es besser das Auslesen in einen Thread zu packen,
Beispiele sind hier: https://stackoverflow.com/questions/...t-receive-text
und hier https://en.delphipraxis.net/topic/40...-tidtcpclient/ zu finden.

Vielleicht kannst Du auch das onWork Event des idTcpClients nutzen?

Grüße
Klaus

gubbe 2. Jan 2025 13:25

AW: Daten abholen bei TCPClient
 
InputBufferIsEmpty wird wahrscheinlich immer True ergeben und somit kommt es nie zum ReadLn.

Der InputBuffer wird erst gefüllt, wenn überhaupt etwas abgefragt wird. Nimm die Prüfung auf InputBufferIsEmpty mal raus, dann wird es wahrscheinlich funktionieren.
Testweise kannst auch probieren, vor dem InputBufferIsEmpty TCPClient.IOHandler.CheckForDataOnSource aufzurufen. Das prüft überhaupt erst, ob ein Daten vorhanden sind.

Die Lösung mit dem Timeout würde ich aber nochmal überdenken. Du hast auch kein richtiges Kriterium dafür, wann die Daten vollständig gelesen wurden. Das könnte z.B. eine empfangene Leerzeile sein oder das Schließen der Verbindung.
Also eine Schleife in der Art "while Connected do"

Sinnvoller ist es aber auf jeden Fall, das ganze in einen Thread auszulagern. Dann kann Du auch direkt ReadLn aufrufen, ohne zu prüfen, ob Daten vorhanden sind, da nur dieser Thread und nicht die Benutzeroberfläche (der Main-Thread) blockiert wird. Das ProcessMessages rauszunehmen hat ja jetzt auch nur bewirkt, das das Programm einfriert, solange auf Daten gewartet wird.

Warum es mit dem Timer trotzdem funktionierte, kann ich nicht sagen. Evtl. wird InputBufferIsEmpty irgendwann nach dem Schließen der Verbindung False und in der Funktion ReadData brichst Du durch den Timeout schon früher ab. Der Timer ist aber auch keine gute Lösung.

Schuby 2. Jan 2025 17:16

AW: Daten abholen bei TCPClient
 
Danke für eure Hilfe.
ich habe mir das mal angeschaut.

https://stackoverflow.com/questions/...t-receive-text
https://en.delphipraxis.net/topic/40...-tidtcpclient/

Aber das ist noch zu hoch für mich, da brauche ich noch ein paar
Jahre um da durch zu blicken.


mfg

gubbe 2. Jan 2025 17:40

AW: Daten abholen bei TCPClient
 
Das Thread-Beispiel aus Stackoverflow ist eigentlich recht übersichtlich. Versuch es doch einfach mal damit und melde Dich, wenn Du Fragen hast.

Wenn Du ein aktuelles Delphi verwendet, würde es noch etwas einfacher gehen mit der Parallel Programming Library. Ich meine, das gab es ab Delphi XE7.

In etwa so (nicht getestet!)

Delphi-Quellcode:
uses System.Threading;

...

Procedure TForm1.Readdata;
var
 aTask: ITask;
begin
 aTask := TTask.Create(
   procedure
   var s: string;
   begin
     while true do
     begin
       s := TCPClient.IOHandler.ReadLn();
       TThread.Synchronize(nil,
       procedure
       begin
          Memo1.lines.add(s);
       end);
     end;
   end);
   aTask.Start;
end;
Da muss natürlich noch eine Abbruchbedingung rein statt dem "while true".

Schuby 2. Jan 2025 18:50

AW: Daten abholen bei TCPClient
 
Liste der Anhänge anzeigen (Anzahl: 1)
Guten abend,
ich habe dein Code mit dem Thread getestet, aber da bekomme ich noch Probleme.
Mein großes Problem ist das ich Daten von einen ESP32 (micro SD Card auslesen) bekomme, aber viele strings mit #13#10

Ich hatte mal vor langer Zeit einen Thread gebastelt und dieser läuft super.
Ich habe es jetzt so gemacht.

Delphi-Quellcode:
procedure TMyThread.Execute;
var i : integer;
Begin
  while bool = true do
  begin
    if Form1.TCPClient.Connected = true then
    begin
      if not Form1.TCPClient.IOHandler.InputBufferIsEmpty then
      begin
        rec_str:= Form1.TCPClient.IOHandler.ReadLn();
        Form1.Edit10.Text:= Form1.Edit10.Text +rec_str;
        Form1.Memo1.Lines.Add(rec_str);
      end;
    end;
  end;
End;

Wenn ich den Befehl ListDir an den ESP32 sende lösche ich vorher Memo1.clear damit ich meinen String
alleine im Memo Feld habe, danach kopiere ich Empfstr:= Memo1.lines.text; in den Empfstr..
Weil ich den Empfstr in meiner Procedure ListBox zerlege.
aber dieser wird nicht kopiert Empfstr ist leer
Deswegen musste ich Edit10 füllen Form1.Edit10.Text:= Form1.Edit10.Text +rec_str;

Jetzt drücke ich eine taste Button10

Delphi-Quellcode:
procedure TForm1.Button10Click(Sender: TObject);
begin
  Empfstr:= memo1.Lines.Text;
  Proc_Fat16_Dir_anzeigen;
end;
Und jetzt wird die Listbox verarbeitet wie im Bild gezeigt.
Was passiert da, bin ich zu schnell im Programm ?
Das Memo1 noch gar keine Daten hat wenn ich meine
Proc_Fat16_Dir_anzeigen; aufrufe ?

Aber so bekomme ich meine daten vom ESP32 sehr gut.

mfg

gubbe 2. Jan 2025 19:12

AW: Daten abholen bei TCPClient
 
Wenn das Readln in meinem Beispiel leere Zeilen zurückgibt, kannst Du die ja ausschließen mit if s<> '' then...
Ich ging davon aus, dass die Funktion erst zurückkehrt, wenn tatsächlich neue Daten gelesen wurden.

In Deinem Thread gibt es noch ein Problem: Du solltest nicht einfach aus dem Thread auf die Controls Memo1 und Edit10 zugreifen. Dafür war das Synchronize in meinem Beispiel da.

In Deinem Beispiel müsste das etwa so aussehen:
Delphi-Quellcode:
        rec_str:= Form1.TCPClient.IOHandler.ReadLn();
 Synchronize(
      procedure
      begin
        Form1.Edit10.Text:= Form1.Edit10.Text +rec_str;
        Form1.Memo1.Lines.Add(rec_str);
      end);
Ich habe nicht ganz verstanden, was Du mit "bin ich zu schnell im Programm" meinst, aber vielleicht ist das damit ja gelöst :)

Schuby 3. Jan 2025 07:47

AW: Daten abholen bei TCPClient
 
Guten morgenm, ich werde mein Problem doch etwas besser beschreiben.
Ich habe an meinen ESP32 eine micro SD Card und diese will ich auch
auslesen. Mit Butten ListDir.

Der Thread Funktioniert Super ich bekomme alle Daten rein.

Delphi-Quellcode:
procedure TMyThread.Execute;
var i : integer;
Begin
  while bool = true do
  begin
    if Form1.TCPClient.Connected = true then
    begin
      if not Form1.TCPClient.IOHandler.InputBufferIsEmpty then
      begin
        rec_str:= Form1.TCPClient.IOHandler.ReadLn();
      Synchronize(
          procedure
          begin
            Dir_List_str:= Dir_List_str +rec_str;
            Form1.Memo1.Lines.Add(rec_str);
          end);
      end;
    end;
  end;
End;
Den Dir_List_str:= ''; leere ich bevor ich den Befehl Form1.TCPClient.IOHandler.Writeln('D' +#12); sende.


Hier meine Button ListDir;
Delphi-Quellcode:
//List Dir
procedure TForm1.ListDirClick(Sender: TObject);
begin
  Dir_List_str:= '';
  memo1.Clear;
  ListBox1.Clear;
  Form1.TCPClient.IOHandler.Writeln('D' +#12);
  showmessage('Dir List eingelesen.!');
  Proc_Fat16_Dir_anzeigen;
end;
jetzt muss ich showmessage('Dir List eingelesen.!'); vorher machen,
mache ich das nicht und gehe dann sofort in Proc_Fat16_Dir_anzeigen.
Ist der Dir_List_str leer.

es ist mir schon klar wenn ich den Befehl Form1.TCPClient.IOHandler.Writeln('D' +#12); sende
das es eine Zeitlang dauert bis die Daten da sind.

Ich denke ich gehe zu schnell in meine Proc_Fat16_Dir_anzeigen;


Ich hoffe ich habe das jetzt besser erklärt.

mfg


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:50 Uhr.
Seite 1 von 3  1 23      

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