Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi max Länge TCPIP (https://www.delphipraxis.net/216803-max-laenge-tcpip.html)

AJ_Oldendorf 5. Mär 2025 11:27

max Länge TCPIP
 
Moin zusammen,
ich habe eine funktionierende Windows Anwendung welche ein Indy TCPServer beinhaltet.
Dann habe ich eine Anwendung auf einem Android Gerät entwickelt mit einem Indy TCPClient.
Beide Anwendungen kommunizieren und können sich Daten hin und her schicken (auch über Internet->feste IP und Port vom Server).

Mir ging es jetzt um das Verständnis TCPIP.
Laut Wiki ist eine maximale Telegramlänge auf 1452 Byte beschränkt.
https://de.wikipedia.org/wiki/Transm...ntrol_Protocol
Ich habe jetzt erwartet, dass bei einem kleinen Test, die Telegramme ab 1452 Byte Länge, auf n-Anzahl Telegramme aufgeteilt wird. Dem ist aber nicht so.
Ich kann sogar 2000 Byte in einem Rutsch übertragen und beim Client kommt das in einem Telegramm an.

Im Client wird der Datenabruf wie folgt in einem extra Thread gemacht:
Execute Funktion:
Delphi-Quellcode:
while not Terminated do
begin
  TCPClient.IOHandler.CheckForDataOnSource(100);
  if not TCPClient.IOHandler.InputBufferIsEmpty then
  begin
    tmpInt := TCPClient.IOHandler.InputBuffer.Size;
    SetLength(content, 0);
    TCPClient.IOHandler.ReadBytes(content, tmpInt, False);   //#$0d + #$0a immer noch am Ende

    tmpStr := 'In: ' + tmpInt.ToString + '->' + BytesToString(content);
    if tmpStr <> '' then
    begin
    if Assigned(OnThreadTCPReceive) then
      OnThreadTCPReceive(Self, tmpStr);
    end;
  end;
end;
Frage 1: Warum können 2000 Byte überhaupt übertragen werden in einem Telegramm? Das ganze geht auch mit 4000 Byte

Ich habe das ganze mal weitergetrieben und bis auf über 5000 Byte Länge gegangen und da bricht er mir manchmal die Telegramme auf 2 Empfangs-Telegramme auf, allerdings ist das erste Telegram nicht immer gleich lang. Es ist also nicht so, dass konstant nach 2000 Byte (fiktive Annahme) ein zweites Telegramm entsteht.

Frage 2: Woher weiß ich beim Empfang, welche Telegramme zusammengehören, wenn das ReceiveEvent mehrmals getriggert wird und immer an unterschiedlicher Stelle ein neues Telegramm erstellt wird?

PS: Ja ich verschicke mit Absicht Bytes und das soll auch so bleiben

QuickAndDirty 5. Mär 2025 11:52

AW: max Länge TCPIP
 
Indy liefert dir einen Datenstrom.
Das kommt zwar alles in TCP Paketen an und und wird in TCP Paketen gesendet, aber entweder das Betriebsystem oder Indy verstecken diese "Mechanik" in einer Blackbox.
z.B. werden pakete zurrück gehalten wenn sie früher eintreffen als ein vor ihnen abgeschicktes Paket, da TCP Pakete ja alle möglichen Wege durchs internet nehmen könnten.
Dann werden z.b. Datenmengen die kleiner sind als eine MTU oft nicht direkt abgeschickt sondern zurrückgehalten in der Hoffnung dass vielleicht noch mehr Daten verschickt werden die dann in dem selben TCP Paket landen können und somit höhere Datenraten sichern. (Nagel algorythmus)

TCP/IP tunnelt deine DATEN, darin musst du selver dein Protokoll bauen.+

z.b. das
AJ_OLDENDORF_TSTRINGS_Protokoll:
Jede Message fängt mit mit einem Zeichen an das nicht #10 ist.
Jede Message endet mit dem zeichen #10#13

oder das AJ_OLDENDORF_FESTELAENGE_Protokoll:
Jede Message ist 1000 zeichen lang.
Die ersten 4 Zeichen enthalten eine Prüfsumme für die folgenden 996 zeichen.

oder das AJ_OLDENDORF_FLEX_Protokoll:
Jede Message ist beginnt mit 4Byte in der die Länger der darauf folgenden Payload kodiert ist.

oder SOAP (= HTTP/HTTPS + XML + SOA Religion)

oder REST (= HTTP/HTTPS + HTTP-Verbs + JSON + Restfull Philosophy + SOA Religion)

USW.

Fehler korrektur kannst Du Dir im Falle von TCP eigentlich sparen, da Reihenfolge und Störungsfreiheit der Daten schon in TCP abgehandelt werden.

Mavarik 5. Mär 2025 13:10

AW: max Länge TCPIP
 
QuickAndDirty hat schon die meisten Antworten geliefert.

Ich mache es immer so (bei reinem TCP/IP)...

While aContext.Connection.IOHandler.Connected do
ein Byte lesen... // ist mein Command_ID
Case Command_ID of

Im case kann ich dann auf verschiede Datenstrukturen oder Befehler zurückgreifen wie:
- Ein Word(len) dann Len Chars
- Ein Commando: Gib mit den File zurück mit dem Namen der zuletzt übermittelt wurde
- Gib mir die Anzahl der Dateien und die Größe zurück
- Welche Version hat Dein Protokoll
- Gib mir Deinen Public Key

usw.

Mavarik :coder:

Hobbycoder 5. Mär 2025 13:14

AW: max Länge TCPIP
 
Übertrag doch mal Text unverschlüsselt und schau dir auf der Windowsmaschine mit einem Packetsniffer die TCP-Pakete an. Da kannst du dann auch die Paketgrößen und den Header gut sehen, was in wievielen Paketen übertragen wird.

AJ_Oldendorf 5. Mär 2025 13:23

AW: max Länge TCPIP
 
Ok danke für die Anregungen / Tipps. Das sollte weiterhelfen

skybibo 5. Mär 2025 17:40

AW: max Länge TCPIP
 
Größere Datenpakete werden von Windows in kleinere Pakete zerteilt. Jedes Paket kann dabei maximal die Größe der MTU annehmen. Dies kann von System zu System leicht variieren. Für die eigene Daten Übertragung bedeutet dies, dass bei einem versenden von z.B. 2000 Byte in der Regel 2 Pakete auf der Empfangsseite ankommen. Diese müssen dann von deinem Programm wieder zusammengefügt werden. Ausnahmen sind spezielle Jumbo Pakete, die auch über 9000 Byte Groß sein können (wird im Switch und bei der Netzwerkschnittstelle konfiguriert. Jumbo Pakete werden in der Regel nur bei speziellen Video Kameras verwendet).

Je nach verwendeten Komponenten wird das zusammenfügen der Daten Pakete auch durch die Komponente erledigt(z.B. Datasnap und Webkomponenten).

Bei Verwendung von TClientSocket/TServerSocket (oder ähnliche z.B. von Indy) muss sich das Programm um das Zusammenführen der Daten Pakete kümmern.

AJ_Oldendorf 6. Mär 2025 09:06

AW: max Länge TCPIP
 
Ich muss doch nochmal nachfragen weil die Aussage von QuickAndDirty mir ein wenig komisch vorkam.
Liefern alle Indy nur einen Datenstrom oder hast du nur TCP/IP Client und Server gemeint?
Hintergrund:
Ich habe für ein ganz anderes Projekt erfolgreich UDP im Einsatz und dort kann ich mit folgenden Befehl

Delphi-Quellcode:
IdUDPClient.SendBuffer(IdUDPClient.Host, IdUDPClient.Port, outMsg);
direkt Telegramme von 32000 Byte verschicken und beim Empfänger kommt auch nur 1x das OnUDPRead Event mit 32000 Byte an.
Klar, dass Betriebssystem zerlegt die Telegramme noch aber fügt sie beim Empfang auch wieder zusammen, sodass ich nur 1x das OnUDPRead Event erhalte.
Das habe ich soeben getestet und ist auch wirklich so.

Bei TCPIP ist es allerdings so, dass ich vom Server (Windows Anwendung) ein 8000 Byte langes Telegramm abschicke und mit der in Post 1 beschrieben Lesefunktion, die Daten abrufe. Allerdings wird das Event mehrmals getriggert, nicht nur 1x. Je nach dem wie mir die Indy die Telegramme aufteilen. Ich hätte eigentlich gerne die gleiche Funktionalität wie bei UDP.
Dort gibt es auch beim Server die Eigenschaft BufferSize, die habe ich auch entsprechend gesetzt. Bei TCPIP gibt es diese nicht. Gibt es einen anderen Weg bei TCPIP, dass ich nur 1x Telegramm abschicke und nur 1x Empfangsevent erhalte, so wie bei UDP?

fisipjm 6. Mär 2025 10:18

AW: max Länge TCPIP
 
Ich bin mir nicht 100% sicher, aber UDP ist ja vom Grundprinzip Verbindungslos, also etwas völlig andere wie TCP.
TCP sorgt dafür das deine Daten auf jeden Fall ankommen, oder du eine Rückmeldung bekommst das dein TCP Paket nicht übermittelt werden konnte. Deswegen müssen auch Headerinformationen und Informationen über die Reigenfolge mit geschickt werden.
UDP Verhält sich das komplett anders. UDP macht "friss oder stirb". Das Paket wird Adressiert und abgeschickt.
Ob der Empfänger existiert, egal.
Ob der Empfänger das Paket erhält, egal.
Welche Reihenfolge, egal.
Hauptsache schnell und da es hier auch keine Fehlerkorrekturen bei Paket Verlusten, Reihenfolgen usw. gibt, kann man das einzelne Paket auch direkt größer schnüren. Deshalb ist die Maximale Paketgröße eines UDP Pakets 65.535

vG
PJM

AJ_Oldendorf 6. Mär 2025 10:35

AW: max Länge TCPIP
 
Hi fisipjm,
du hast mit allen UDP Informationen Recht bzgl UDP.
Mir ist nur nicht klar, warum diese Überprüfungen und Mechanismen bei TCPIP im Hintergrund nicht möglich sind und am Ende dann dennoch nur ein Telegramm im ReceiveEvent ausgelöst wird. Die Handlingsschicht dazwischen weiß doch, dass es das eine Telegramm auf 3 aufgesplittet hat und kann diese beim Empfang auch wieder zusammensetzen

QuickAndDirty 6. Mär 2025 12:33

AW: max Länge TCPIP
 
Zitat:

Zitat von AJ_Oldendorf (Beitrag 1546871)
Ich muss doch nochmal nachfragen weil die Aussage von QuickAndDirty mir ein wenig komisch vorkam.
Liefern alle Indy nur einen Datenstrom oder hast du nur TCP/IP Client und Server gemeint?
Hintergrund:
Ich habe für ein ganz anderes Projekt erfolgreich UDP im Einsatz und dort kann ich mit folgenden Befehl

Delphi-Quellcode:
IdUDPClient.SendBuffer(IdUDPClient.Host, IdUDPClient.Port, outMsg);
direkt Telegramme von 32000 Byte verschicken und beim Empfänger kommt auch nur 1x das OnUDPRead Event mit 32000 Byte an.
Klar, dass Betriebssystem zerlegt die Telegramme noch aber fügt sie beim Empfang auch wieder zusammen, sodass ich nur 1x das OnUDPRead Event erhalte.
Das habe ich soeben getestet und ist auch wirklich so.

Bei TCPIP ist es allerdings so, dass ich vom Server (Windows Anwendung) ein 8000 Byte langes Telegramm abschicke und mit der in Post 1 beschrieben Lesefunktion, die Daten abrufe. Allerdings wird das Event mehrmals getriggert, nicht nur 1x. Je nach dem wie mir die Indy die Telegramme aufteilen. Ich hätte eigentlich gerne die gleiche Funktionalität wie bei UDP.
Dort gibt es auch beim Server die Eigenschaft BufferSize, die habe ich auch entsprechend gesetzt. Bei TCPIP gibt es diese nicht. Gibt es einen anderen Weg bei TCPIP, dass ich nur 1x Telegramm abschicke und nur 1x Empfangsevent erhalte, so wie bei UDP?

TIDTCPClient, TIDTCPServer, TIDUDPClient und TIDUDPServer liefern einfach nur einen Datenstrom.
Die SOAP Clients und Soap Server von INDY liefern naturlich SoapRequest und SoapResponses...
http clients und http server liefern HttpRequests und HttpResponses.

Ich weiß nicht genau wann OnUDPRead gefeuert wird, aber ich vermute mal das passiert wenn der Readbuffer eine bestimmte zeit nicht mehr gefüllt wurde oder Voll ist. So würde ich es machen. Da UDP eine paketlänge codiert kann es natürlch sein, dass deine Message genau ein einziges OnUDPRead event auslöst sobald ein Paket vollständig gelesen wurde...aber es muss nicht zwinged so sein das eine Payload nur in einem einzigen UDP paket gesendet wird!
Bei TCP wird die länge/größe der Pakete dynamisch an die Qualität der Leitung angepasst.
Ich würde mich in keinem Fall auf Mechanismen der darunter liegenden Protkolle verlassen!

omnibrain 6. Mär 2025 12:50

AW: max Länge TCPIP
 
Du musst erstmal etwas grundsätzliches verstehen:
TCP ist einfach nur ein "Stream of Bytes", das heißt eine Kette von einzelnen Bytes. Es gibt auch keine TCP-Pakete, sondern nur Segmente. Diese Segmente sind einfach Teile des Datenstroms. Das ist nichts, was von höheren Protokollen oder Ebenen kontrolliert wird. Das macht die Hardware, mit ihrer Firmware und ggf. noch dem Treiber, eventuell konfiguriert durch das OS unter sich ab.

Alles darüber sind höchsten "leaky abstractions". Wenn du beispielsweise in deiner Komponente definierst, dass du feste Line-Endings benutzt, dann sammelt die einfach was ankommt ein bis dieses Zeichen auftaucht und stellt es dir bereit. Gleichzeitig ist wenn du etwas mit festem Line-Ending sendest eben nicht garantiert, dass das alles in einem Segment rausgeht oder ankommt.
Wenn du ohne Line-Ending arbeitest, dann musst du entweder ein Protokoll mit fester "Message"-Größe entwerfern und dann immer so viele Bytes lesen wie du brauchst, ein Protokoll entwerfen bei dem (am besten am Anfang) die Information mitkommt wie viele Bytes noch gelesen werden müssen, oder eben einen komplexen Parser bauen, wenn beides nicht möglich ist.

UDP hingegen arbeitet mit einzelnen Datagrammen. Dafür hat man keinerlei Garantie in welcher Reihenfolge diese ankommen, oder ob sie überhaupt ankommen.
Falls es dir auf einzelne Datagramme ankommt, dann kannst du UDP nutzen und musst ggf. sowas wie Reihenfolge-Management oder gar Re-Transmit selbst in deinem Protokoll implementieren.

Oder: Du nutzt nicht TCP "direkt", sondern nutzt ein ganz anderes Protokoll, was dir mehr Arbeit abnimmt. Ich nutze gerne *MQ-Protokolle wie MQTT oder Zero-MQ.
Ein anderer Tipp ist Server oder Client auch mal in einer anderen Programmiersprache eventuell gar durch eine andere Person implementieren zu lassen. Du glaubst nicht, was man da für Fehler findet...

AJ_Oldendorf 6. Mär 2025 14:22

AW: max Länge TCPIP
 
Danke omnibrain und QuickAndDirty für eure Infos.
Soweit bin ich bei euch und kann es auch bestätigen bzw sind mir die UDP Mechanismen klar.
Bei einem Satz bin ich hellhörig geworden:

Zitat:

Wenn du ohne Line-Ending arbeitest...
Angenommen, ich würde mit einem Line-Ending arbeiten, dann könnte ich die Telegramme ja so ausstatten, dass immer am Telegrammende ein oder 2 entsprechende Zeichen sind, die sonst nie vorkommen können. Dann könnte der Client genau auf diese 2 Zeichen "warten" und dann alles zusammen ausgeben.
Wäre das so?
Wenn ja, wie würde der Empfang aussehen, wenn man auf ein bestimmtes Line-Ending wartet?

omnibrain 6. Mär 2025 14:54

AW: max Länge TCPIP
 
Zitat:

Zitat von AJ_Oldendorf (Beitrag 1546881)
Angenommen, ich würde mit einem Line-Ending arbeiten, dann könnte ich die Telegramme ja so ausstatten, dass immer am Telegrammende ein oder 2 entsprechende Zeichen sind, die sonst nie vorkommen können. Dann könnte der Client genau auf diese 2 Zeichen "warten" und dann alles zusammen ausgeben.
Wäre das so?

Ja genau, du liest solange Bytes bis das Ende kommt. Ob du einen Puffer oder ähnliches brauchst hängt von der Implementierung ab.

Ich benutze an der Stelle dann immer ICS, das hat den "LineMode" eingebaut. In dem Fall macht die Komponente das. https://wiki.overbyte.eu/wiki/index....ket.ReceiveStr

jaenicke 6. Mär 2025 19:25

AW: max Länge TCPIP
 
Zitat:

Zitat von AJ_Oldendorf (Beitrag 1546881)
Wenn ja, wie würde der Empfang aussehen, wenn man auf ein bestimmtes Line-Ending wartet?

Dazu haben QuickAndDirty und Mavarik oben schon etwas gesagt.

Stell dir ein Buch vor:
Du gehst Zeile für Zeile durch und erkennst an der Positionierung und Formatierung, wann du eine Seitenzahl und wann ein neues Kapitel vor dir hast. Aber du liest das Buch dabei einfach von vorne bis hinten, ohne dass du auf bestimmte Kennzeichen wartest.

Und genauso geht man auch bei einer solchen Übertragung vor. Stell dir ein ganz einfaches Protokoll vor: # ist der Start einer Überschrift, $ der Start einer Seitenzahl, am, - startet einen Text und Ende kommt immer ein *.

Beispiel:
$1*#Überschrift*-Das ist ein Text.$2*-Und noch mehr Text!**$44*#Überschrift*-Das ist ein kleiner Text.$45*-Und noch ein wenig Text!**

Nun bekommst du:
$1*#Überschrift*-Das ist e
Dann gehst du zeichenweise durch und fügst die Zeichen einzeln zu deinem Empfangspuffer (sprich eine Stringvariable) hinzu. Findest du ein doppeltes **, also dein Paketende, gibst du deinen Empfangspuffer als vollständiges Paket weiter und leerst ihn. Das machst du einfach immer so weiter, wenn du etwas empfängst. In diesem Fall wäre das Paket nicht vollständig, also wartest du weiter, bis du den nächsten Teil empfängst.

Pseudocode in etwa:
Code:
Buffer := '';
while Connection.Active do
begin
  if Connection.HasData then
  begin
    Data := Connection.GetData;
    FoundEndChar := False;
    for i := 1 do Length(Data) do
    begin
      Buffer := Buffer + Data[i];
      if Data[i] = EndeZeichen then
        if FoundEndChar then // das letzte Zeichen war schon ein EndeZeichen --> doppeltes Ende gefunden
        begin
          VerarbeitePaket(Buffer);
          Buffer := '';
          FoundEndChar := False;
        end
        else
          FoundEndChar := True // ein erstes EndeZeichen
      else
        FoundEndChar := False; // egal ob vorher ein einzelnes war oder nicht, aktuell kein EndeZeichen
    end;  
  end
  else
    Sleep(1); // kurz warten, damit die Schleife nicht so viel Leistung zieht
end;
Und zur Analyse: Du gehst durch...
$ --> Seitenzahl, also fängt ein Paket an.
1 --> Aktueller Status ist Seitenzahl
* --> Aktueller Status ist Seitenzahl, die ist damit vollständig --> Seite "2"
# --> Überschrift beginnt
Ü...t --> Überschriftsinhalt
* --> Überschrift beendet --> "Überschrift"
- --> Text beginnt
D..e --> weiterer Text

An der Stelle weißt du, dass das Paket noch nicht vollständig ist. Also wartest du auf den nächsten Teil, packst den hinten dran und prüfst erneut.

Und so gehst du einfach zeichenweise durch, merkst dir, wo du bist, prüfst, ob der nächste Inhalt so im Zusammenhang passt, ...
Am Ende bist du dann am ersten Sternchen, bist im Modus "im Paket" und bekommst das zweite Sternchen. Damit ist das Paket vollständig und du kannst es zur Bearbeitung weitergeben.

Das ist eine Möglichkeit. Das Prinzip nennt sich endlicher Automat. Du kannst die schon vorhandenen Teile des Pakets dabei direkt in einer Struktur ablegen und aus deinem Empfangsstring entfernen oder du machst das erst, wenn du das Ende hast.

Du kannst aber auch wie oben schon angesprochen wurde, die Länge direkt am Anfang mitschicken. Dann weißt du, wie viele Bytes danach kommen. Du kannst z.B. eine Überschrift so aussehen lassen:
PAKET54*#11*Überschrift*
PAKET --> neues Paket
5..4 --> Paketlänge
* --> Paket ist 54 Bytes lang
# --> Überschrift Start
1..1 --> Länge
* --> Überschrift ist 11 Bytes lang
...

Es gibt wirklich viele Möglichkeiten und das ist nur ein ganz kurzer Einstieg, damit du eine grundsätzliche Idee hast, wie du mit Datenströmen arbeiten kannst. Es gibt natürlich andere und sicher auch schönere Lösungen.

Die ganz simple Variante wäre, mit Pos in dem String nach dem Endezeichen zu suchen.

AJ_Oldendorf 7. Mär 2025 06:29

AW: max Länge TCPIP
 
Moin zusammen,
@jaenicke: Also das ist mir schon generell klar, wie ein grober einfacher Ablauf wäre. Mir ging es eigentlich eher darum, ob Indy bzgl. Line-Ending nicht schon etwas mitliefert? Ich will das ganze ja auch in einem Thread ausgelagert laufen lassen und darauf war meine Frage eigentlich abgezielt, wie es dann konkret mit Indy aussehen könnte.

Ich habe jetzt folgendes Konstrukt mit Indy umgesetzt und ich werde damit weitere Tests durchführen:

Server-Senden:
Server hat seinen String (Daten) und hängt am Ende immer fixe 4 Sonderzeichen an.
Das ganze wird in TIdBytes konvertiert und mit .Write verschickt.

Client-Empfang:
Der Client prüft, ob sein InputBuffer nicht leer ist und liest mittels
Delphi-Quellcode:
TCPClient.IOHandler.ReadLn('hier stehen meine 4 fixen Sonderzeichen');
die Daten ein.
Das heißt, der Client liest den InputBuffer immer bis zum Terminator und liefert mir dann erst den Datenstrom. Damit habe ich, Stand jetzt, immer ein Telegram (egal wie lang dieses ist).

Client-Senden:
Client hat seinen String (Daten) und hängt am Ende immer die gleichen fixen 4 Sonderzeichen an.
Das ganze wird in TIdBytes konvertiert und mit .Write verschickt.

Server-Empfang:
Dieser hat sein Execute-Event und prüft darin ebenfalls ob sein InputBuffer nicht leer ist und liest mittels
Delphi-Quellcode:
AContext.Connection.IOHandler.ReadLn('hier stehen meine 4 fixen Sonderzeichen');
die Daten ein.
Das heißt, der Server liest den InputBuffer immer bis zum Terminator und liefert mir dann erst den Datenstrom. Damit habe ich, Stand jetzt, immer ein Telegram (egal wie lang dieses ist).

Scheint bisher zu funktionieren aber wie gesagt, damit werde ich weiter testen

jaenicke 7. Mär 2025 07:36

AW: max Länge TCPIP
 
Wenn du ReadLn ohne Timeout nutzt, hängt der Thread an der Stelle. Dann kannst du ihn nicht sauber beenden. Du solltest ein Timeout mitgeben, damit du trotzdem noch auf Terminated prüfen und die Empfangsschleife beenden kannst.

QuickAndDirty 7. Mär 2025 10:45

AW: max Länge TCPIP
 
Wenn sie auf beiden Seiten bekannt sind, dann
kann man übrigens auch einfach "Datenobjekte" serialisieren z.B. ins JSON und am anderen Ende wieder Deserialisieren.
Erweitertem RTTI und JSON units.
Es gibt einige fertige JSON-Serializer/Deserializer Biblioteken da draußen...

Bbommel 7. Mär 2025 10:58

AW: max Länge TCPIP
 
Ich habe selbst auch Code, der zeilenweise liest, und auf die Art seit 17 Jahren problemlos funktioniert. Daher habe ich gerade mal geschaut, ob ich bei mir noch etwas finde, was ich hilfreiches schreiben könnte, aber eigentlich ist alles gesagt. Was mir aber aufgefallen ist: bei mir steht:

Delphi-Quellcode:
Result:=tcpConnection.Socket.ReadLn('',aTimeOut,-1,useIndyEncoding);

Bei mir steht also
Delphi-Quellcode:
tcpConnection.Socket
statt
Delphi-Quellcode:
tcpConnection.IOHandler
. Weiß jemand, ob das ein Unterschied ist (tcpConnection ist TIdTCPClient und hätte auch den IOHandler)?

AJ_Oldendorf 10. Mär 2025 06:36

AW: max Länge TCPIP
 
@jaenicke: Danke für den Hinweis mit dem Timeout. Ich verstehe was du meinst aber wenn ich vorher den InputBuffer auf <> Empty abfrage, dann bleibt mein Thread mit dem ReadLn nur bis zum nächsten gelesen Terminator hängen. Richtig? Auf welchen Wert sollte man das Timeout denn setzen? Erfahrungen? Was passiert, wenn Timeout abläuft und er nicht bis zum Terminator gelesen hat? Bekomme ich dann wieder nur ein Teilstring von meinem Telegramm?

@QuickAndDirty: Das sagt mir erstmal gar nichts dein Vorschlag :shock: Wie würde denn sowas genau aussehen und was meinst du mit "Wenn sie auf beiden Seiten bekannt sind, dann"? Also die Telegramme sind immer inhaltlich unterschiedlich und auch immer unterschiedlich lang

QuickAndDirty 10. Mär 2025 10:58

AW: max Länge TCPIP
 
Zitat:

Zitat von AJ_Oldendorf (Beitrag 1546939)
@QuickAndDirty: Das sagt mir erstmal gar nichts dein Vorschlag :shock: Wie würde denn sowas genau aussehen und was meinst du mit "Wenn sie auf beiden Seiten bekannt sind, dann"? Also die Telegramme sind immer inhaltlich unterschiedlich und auch immer unterschiedlich lang

Wenn du einen Typ TTermin hast welcher von TPersistent oder so abgeleitet ist, dann kannst du Instanzen dieses Typs mittels RTTI nach Json "serialisieren" und wenn du am anderen ende die Unit wo der Typ deklariert ist auch eingebunden hast, dann kannst du den JSON String auch wieder in ein Objekt umwandeln aka Deserialisieren.
Wenn man einmal Das serialisieren mittels RTTI und JSON programmiert hat, funktioniert das für alle Objekte die gewisse Regeln einhalten und so kannst du alles mögliche an Typen in strings umwandeln verschicken und wieder in Objekte umwandeln...ohne das du es für jeden einzelfall neu programmieren musst.

jaenicke 10. Mär 2025 11:51

AW: max Länge TCPIP
 
Zitat:

Zitat von AJ_Oldendorf (Beitrag 1546939)
Ich verstehe was du meinst aber wenn ich vorher den InputBuffer auf <> Empty abfrage, dann bleibt mein Thread mit dem ReadLn nur bis zum nächsten gelesen Terminator hängen. Richtig?

Ja, schon, aber wenn keine Daten mehr kommen, wartet die Funktion einfach weiter. Wenn du das Programm dann beenden möchtest, kannst du den Lesevorgang nicht sauber beenden.

Zitat:

Zitat von AJ_Oldendorf (Beitrag 1546939)
Auf welchen Wert sollte man das Timeout denn setzen? Erfahrungen?

Das kommt auf die Größe der Pakete an und wie lange es dauern darf, bis der Thread sich auf Anforderung beendet. Ich nehme meistens 100 bis 500 Millisekunden, weil das die Verzögerung gering genug hält, dass niemand beim Beenden bewusst warten muss, andererseits aber auch nicht zu oft versucht wird zu lesen.

Zitat:

Zitat von AJ_Oldendorf (Beitrag 1546939)
Was passiert, wenn Timeout abläuft und er nicht bis zum Terminator gelesen hat? Bekomme ich dann wieder nur ein Teilstring von meinem Telegramm?

Das kannst du ja leicht testen. Soweit ich mich erinnere, wird der schon angekommene Teil nicht zurückgeliefert, sprich du bekommst einen Leerstring und beim nächsten Aufruf alles. Du kannst aber prüfen, ob ein Timeout aufgetreten ist, indem du ReadLnTimedOut abfragst.

AJ_Oldendorf 11. Mär 2025 08:35

AW: max Länge TCPIP
 
@jaenicke:
Danke, ich prüfe das mal mit dem Leerstring und dem Timeout.

Sag mal, beim Server ist es aktuell so, dass wenn sich ein Client verbunden hat, die CPU Auslastung auf ca 6% von dem Programm geht.
Es werden keine Daten verschickt vom Server und vom Client. Einfach nur das Verbinden.
Wenn ich beim Server das Active auf False setze, geht die Auslastung sofort runter.
Hat jemand eine Idee dazu?

jaenicke 11. Mär 2025 08:52

AW: max Länge TCPIP
 
Zum Server lässt sich ohne Quelltext nicht viel sagen. Du kannst nur mal zwischendurch anhalten und schauen, wo du gerade bist.

Hast du vielleicht ein OnExecute mit Schleife, in der du kein Sleep(1) drin hast (wenn keine Anfrage da war), um die Schleifendurchläufe im Leerlauf zu begrenzen?

AJ_Oldendorf 11. Mär 2025 09:16

AW: max Länge TCPIP
 
Also ich habe eine Form mit TIdTCPServer und verknüpften TIdServerIOHandlerStack.

Delphi-Quellcode:
procedure TMyForm.FormCreate(Sender: TObject);
begin
  IdTCPServer1.DefaultPort := 44001;
end;

procedure TMyForm.FormDestroy(Sender: TObject);
begin
  IdTCPServer1.Active := False;
end;

procedure TMyForm.IdTCPServer1Connect(AContext: TIdContext);
begin
  if Assigned(LogSL) then
  begin
    LogSL.Add('A client connected');
  end;
end;

procedure TMyForm.IdTCPServer1Disconnect(AContext: TIdContext);
begin
  if Assigned(LogSL) then
  begin
    LogSL.Add('A client disconnected');
  end;
end;

procedure TMyForm.IdTCPServer1Exception(AContext: TIdContext;
  AException: Exception);
begin
  if Assigned(LogSL) then
  begin
    LogSL.Add('A exception happend !');
  end;
end;

procedure TMyForm.IdTCPServer1Execute(AContext: TIdContext);
var
  tmpStr : String;
begin
  if IdTCPServer1.Active then
  begin
    if not AContext.Connection.IOHandler.InputBufferIsEmpty then
    begin
      tmpStr := AContext.Connection.IOHandler.ReadLn('#~#*', 300, -1);
      LogSL.Add(tmpStr);

      Timer1.Enabled := True;
    end;
  end;
end;
Das ist im groben alles...

jaenicke 11. Mär 2025 11:48

AW: max Länge TCPIP
 
Pack mal am Ende des OnExecute ein Sleep(1) rein oder verwende
Delphi-Quellcode:
AContext.Connection.IOHandler.CheckForDataOnSource(10);
, damit die Anzahl der Aufrufe reduziert wird, dann sollte das nicht mehr passieren.

AJ_Oldendorf 11. Mär 2025 13:39

AW: max Länge TCPIP
 
Der Aufruf von
Delphi-Quellcode:
AContext.Connection.IOHandler.CheckForDataOnSource(10);
vor dem
Delphi-Quellcode:
if not AContext.Connection.IOHandler.InputBufferIsEmpty then
hat geholfen bzgl der CPU Auslastung.
Du meintest ja sicherlich davor aufrufen oder?

Wie ist es beim Client?
Da habe ich das mit der CPU Auslastung bisher nicht festgestellt (der Lesevorgang mit "InputBufferIsEmpty" und "ReadLn" ist dort auch in einem Thread ausgelagert).
Sollte man dort auch
Delphi-Quellcode:
TCPClient.IOHandler.CheckForDataOnSource(10);
aufrufen?

Sleep(1) wird nicht gebraucht :-)

jaenicke 11. Mär 2025 13:46

AW: max Länge TCPIP
 
Sehr gut, ja, ich meinte davor aufrufen. Und Sleep(1) war nur eine Alternative, die brauchst du dann nicht, nein.

Im Client brauchst du das nicht, wenn du ReadLn verwendest. Wenn nicht, eines der beiden schon, so habe ich es ja auch in meinem Codebeispiel drin (das Sleep).

AJ_Oldendorf 11. Mär 2025 13:59

AW: max Länge TCPIP
 
Ja ich verwende im Client das ReadLn. Hatte nur gefragt, da ich es ja im Server auch verwende das ReadLn.

Danke für die Unterstützung bisher


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:26 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 by Thomas Breitkreuz