AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

max Länge TCPIP

Ein Thema von AJ_Oldendorf · begonnen am 5. Mär 2025 · letzter Beitrag vom 10. Mär 2025
Antwort Antwort
Seite 2 von 3     12 3      
omnibrain

Registriert seit: 11. Nov 2022
81 Beiträge
 
Delphi 11 Alexandria
 
#11

AW: max Länge TCPIP

  Alt 6. Mär 2025, 12:50
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...
  Mit Zitat antworten Zitat
AJ_Oldendorf

Registriert seit: 12. Jun 2009
404 Beiträge
 
Delphi 12 Athens
 
#12

AW: max Länge TCPIP

  Alt 6. Mär 2025, 14:22
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?
  Mit Zitat antworten Zitat
omnibrain

Registriert seit: 11. Nov 2022
81 Beiträge
 
Delphi 11 Alexandria
 
#13

AW: max Länge TCPIP

  Alt 6. Mär 2025, 14:54
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
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.837 Beiträge
 
Delphi 12 Athens
 
#14

AW: max Länge TCPIP

  Alt 6. Mär 2025, 19:25
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.
Sebastian Jänicke
AppCentral

Geändert von jaenicke ( 6. Mär 2025 um 19:28 Uhr)
  Mit Zitat antworten Zitat
AJ_Oldendorf

Registriert seit: 12. Jun 2009
404 Beiträge
 
Delphi 12 Athens
 
#15

AW: max Länge TCPIP

  Alt 7. Mär 2025, 06:29
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 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 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
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.837 Beiträge
 
Delphi 12 Athens
 
#16

AW: max Länge TCPIP

  Alt 7. Mär 2025, 07:36
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.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.981 Beiträge
 
Delphi 12 Athens
 
#17

AW: max Länge TCPIP

  Alt 7. Mär 2025, 10:45
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...
Andreas
Monads? Wtf are Monads?

Geändert von QuickAndDirty ( 7. Mär 2025 um 10:51 Uhr)
  Mit Zitat antworten Zitat
Bbommel

Registriert seit: 27. Jun 2007
Ort: Köln
665 Beiträge
 
Delphi 12 Athens
 
#18

AW: max Länge TCPIP

  Alt 7. Mär 2025, 10:58
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:

Result:=tcpConnection.Socket.ReadLn('',aTimeOut,-1,useIndyEncoding);
Bei mir steht also tcpConnection.Socket statt tcpConnection.IOHandler . Weiß jemand, ob das ein Unterschied ist (tcpConnection ist TIdTCPClient und hätte auch den IOHandler)?
  Mit Zitat antworten Zitat
AJ_Oldendorf

Registriert seit: 12. Jun 2009
404 Beiträge
 
Delphi 12 Athens
 
#19

AW: max Länge TCPIP

  Alt Heute, 06:36
@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 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
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.981 Beiträge
 
Delphi 12 Athens
 
#20

AW: max Länge TCPIP

  Alt Heute, 10:58
@QuickAndDirty: Das sagt mir erstmal gar nichts dein Vorschlag 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.
Andreas
Monads? Wtf are Monads?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:36 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