Hallo zusammen,
ich habe mal die ein oder andere Frage zur Datenübertragung mit TCP und
UDP.
Und zwar möchte ich mir von einem Server zyklisch Daten in einem
Intervall von z.B. 20 ms zuschicken lassen.
Der Client soll in einer Art Spielumgebung laufen.
Bei Start der Berechnung eines neuen Frames, sollen aktuelle Daten vom
Server anliegen. Nach der Berechnung sollen ebenfalls Daten an den
Server zurückgeschrieben werden. Danach wird das Bild gerendert und der
Zyklus startet von vorn.
Jetzt könnte der Client dem Server bei Start des Spiels sagen, er solle
die Daten im 10 ms Zyklus schicken damit diese auf jeden Fall bei jedem
Frame aktuell sind.
Damit es nicht zu Verzögerungen kommt, will ich nicht bei jedem Zyklus
eine Anfrage schicken und dann auf Antwort warten.
Jetzt frage ich mich: wenn der Client nur alle 20 ms abruft, sind dann
zwei Datensätze im Puffer?
Oder bekommt der Server erst eine Bestätigung dass die Daten angekommen
sind, wenn der Client die Daten ausliest?
Und wie sieht das bei UDP aus: Könnte der Server sozusagen mit "Vollgas"
senden, und der Client fischt sich immer das letzte Paket aus dem
Puffer?
Gruß
Thomas
Thomas schrieb:> Jetzt frage ich mich: wenn der Client nur alle 20 ms abruft, sind dann> zwei Datensätze im Puffer?
Zunächst ja.
> Oder bekommt der Server erst eine Bestätigung dass die Daten angekommen> sind, wenn der Client die Daten ausliest?
Auch. Irgenwann sind halt alle beteiligten Puffer voll.
> Und wie sieht das bei UDP aus: Könnte der Server sozusagen mit "Vollgas"> senden, und der Client fischt sich immer das letzte Paket aus dem> Puffer?
Auch da gibt es Puffer.
Zunächst muss dir klar werden, dass TCP in solchen isochronen
Übertragungen nicht erste Wahl ist. TCP überträgt gnadenlos in der
richtigen Reihenfolge. Auch wenn der Inhalt veraltet ist und niemanden
mehr interessiert. Weshalb TCP beispielsweise bei Sprachübertragung
(VoIP) nicht sinnvoll ist.
Wenn wie hier immer nur der letzte Stand interessiert, dann ist die
Basis UDP (oder eines der exotischeren anderen Protokolle). Ein
sinnvoller Ablauf kann sein, dass der Sender alle 10ms seinen Frame
sendet und beim Empfänger ein Thread nur dafür zuständig ist, den
letzten Frame in einen von zwei alternierenden Puffern im RAM zu
schreiben. Dann ist im RAM immer der letzte Frame vorrätig -
Übertragungsfehler inklusive. Wenn das eigentliche Programm auf
Empfängerseite nicht mitkommt, dann tut das nichts zu Sache, dann wird
halt mal ein empfangener Frame ignoriert.
UDP bedeutet schlicht das keine Garantie übernommen wird, das einmal
gesendete Daten auch ankommen. Wenn was gesendet wird, aber nicht
ankommt, dann ist das so. Wird z.B. bei Streaming verwendet.
Bei TCP läuft das so, dass ein Paket, das nicht beim Empfänger ankommt,
vom Empfänger neu angefragt wird.
Was du wie, wann, wo mit den Daten machst, ist ja deine Sache. Ob du da
nun das letze oder erste oder 12503 Paket aus irgend einem Puffer holst,
is ja dein Ding.
Grüße
PS: Mit "Frame" dürfte in diesem Kontext ein komplettes Bild gemeint
sein, oder? Ist etwas missverständlich, weil Ethernet-Pakete ebenfalls
als Frames bezeichnet werden.
Ja, mit Frame ist in diesem Fall ein Bild gemeint.
Ich hatte über UDP mit Prüfsumme und einer Sequenznummer die in jedem
Telegramm erhöht wird auch schon nachgedacht.
Es wird dann im Client nur das Datenpaket mit der höchsten Nummer
ausgewertet. Ältere Pakete oder welche mit einem Prüfsummenfehler werden
schlicht verworfen.
Ich schreib nochmal genauer was ich vorhabe:
Das ist kein Spiel im eigentlichen sinne, sondern es wird das Unreal
Development Kit (UDK) eine zur Simulation einer Maschine benutzt. Die
Steuerung dieser Maschine übernimmt eine SPS.
Ich habe das Prinzip schon laufen, nur ist es momentan so, dass aus dem
UDK über eine dll lokal auf dem Rechner mit der SPS kommuniziert wird.
Das will ich jetzt auf Netzwerk ändern, weil fürs UDK ein PC mit guter
Grafikkarte benötigt wird, und damit man das System relativ einfach an
diverse andere Steuerungen oder auch Microcontroller anbinden kann.
Darum sollte gewährleistet sein, dass auf jeden Fall zu jedem Bild-Frame
die Daten aus der Steuerung aktuell vorliegen.
Wie groß ist denn der interne Datenpuffer? Ich würde mal schätzen dass
ein Datenpaket im Höchstfall (1000 Variablen) bis zu 50 kByte groß
werden kann.
Thomas schrieb:> Wie groß ist denn der interne Datenpuffer?
Wenn du das wissen musst, dann hast du schon verloren. Das ist weder
klar definiert, noch ist es auf dem gleichen System stets gleich.
A. K. schrieb:> Wenn du das wissen musst, dann hast du schon verloren. Das ist weder> klar definiert, noch ist es auf dem gleichen System stets gleich.
"Muss" nicht. Aber für eine Abschätzung ob es bei einem Client-Zyklus
mit 20 ms sinnvoll ist, alle 1 ms Daten zu schicken.
Ich habe damit so gut wie keine Erfahrung. Ich stelle mir nur vor, der
Puffer ist voll und dann ist das letzte Paket nur noch halb vorhanden.
Na gut, dann wird eben das Paket davor verwendet. Wichtig ist nur dass
so ein Paket auf jeden Fall komplett in den Puffer passt.
Thomas schrieb:> "Muss" nicht. Aber für eine Abschätzung ob es bei einem Client-Zyklus> mit 20 ms sinnvoll ist, alle 1 ms Daten zu schicken.
Wie ich schon schrieb: Wenn du Puffer brauchst, dann mach dir welche.
Selber. Schreib einen Thread, der nix anderes tut als Daten zu empfangen
und ins RAM zu legen. In wieviele Kilo-, Mega- oder Gigabytes auch
immer.
> Ich habe damit so gut wie keine Erfahrung. Ich stelle mir nur vor, der> Puffer ist voll und dann ist das letzte Paket nur noch halb vorhanden.
Deshalb hatte ich vorhin alternierende Bildspeicher vorgeschlagen. Einer
ist voll, der andere wird grad eben oder demnächst gefüllt und ist daher
in undefiniertem Zustand. Halbe Ethernet-Frames gibts aber nicht. Die
gibts nur ganz oder garnicht.
Thomas schrieb:> "Muss" nicht. Aber für eine Abschätzung ob es bei einem Client-Zyklus> mit 20 ms sinnvoll ist, alle 1 ms Daten zu schicken.
Was definitiv nicht sinnvoll ist: Mehr Daten zu schicken als der
Empfänger aus dem Network-Stack abholt, in der Hoffnung, dass dabei
zufällig genau jene Daten ankommen, die du haben willst.
Also: Bau das so, dass dein Empfängerprogramm alle Daten kriegt, die der
Sender schickt. Wenn du dann welche verwerfen willst, dann tu es selbst.
Nur dann hast du Kontrolle darüber, welche das sind.
A. K. schrieb:> Deshalb hatte ich vorhin alternierende Bildspeicher vorgeschlagen. Einer> ist voll, der andere wird grad eben oder demnächst gefüllt und ist daher> in undefiniertem Zustand.
Das ist schonmal eine gute Idee. Wenn aus irgendeinem Grund das Netzwerk
mal kurzzeitig haken sollte, dann hat das auch keine Auswirkungen auf
das Spiel.
Generell scheint UDP für diesen Anwendungsfall also geeigneter zu sein.
Nur werde ich dann quasi als Befehlskanal noch eine zweite Verbindung
über TCP aufbauen müssen, denn diese Daten sollten schon auf jeden Fall
ankommen.
Und Daten vom Client an den Server sollten auch definitiv ankommen,
falls z.B. ein Gegenstand vor einer Lichtschranke nur für ein Bild-Frame
steht.
Thomas schrieb:> Nur werde ich dann quasi als Befehlskanal noch eine zweite Verbindung> über TCP aufbauen müssen, denn diese Daten sollten schon auf jeden Fall> ankommen.
Und - O Wunder! - genau so arbeiten VoIP und Videotelefonie. SIP oder
H323 per TCP für die Steuerung und RTP per UDP für Sprach/Video-Stream.
Thomas schrieb:> Generell scheint UDP für diesen Anwendungsfall also geeigneter zu sein.> Nur werde ich dann quasi als Befehlskanal noch eine zweite Verbindung> über TCP aufbauen müssen, denn diese Daten sollten schon auf jeden Fall> ankommen.> Und Daten vom Client an den Server sollten auch definitiv ankommen,> falls z.B. ein Gegenstand vor einer Lichtschranke nur für ein Bild-Frame> steht.
Du mußt dir halt im Klaren darüber sein, daß bei Paketverlust dieses
Paket natürlich dann verzögert ankommt, nachdem es eben nochmal
angefordert und erneut gesendet wurde, und daß sämtliche Pakete, die
danach gesendet werden, so lange verzögert werden, bis das fehlende
Paket nachgeliefert wurde. Die sind dann evt. zwar schon am
Emfängerrechner angekommen, werden aber von dessen IP-Stack
zurückgehalten.
Rolf Magnus schrieb:> daß bei Paketverlust
TCP ist Streamorientiert, UPD Paketorientiert, daher kriegt man auf
Anwendungsschicht eh nix von Paketen mit, da muss man sich selber drum
bemühen Pakete zu erkennen, das sollte man auch im Hinterkopf behalten.
Jürgen Liegner schrieb:> Wenn man nur UDP braucht ist der GPLV2 Stack, den es mit/bei FreeRTOS> gibt, sicher auch mal einen Blick wert.
Gehts hier nicht um "PC-Programmierung", Spiele(-Server) usw?
Ich denk mal, jedes dafür in Frage kommende Betriebsystem wird schon
einen UDP-Stack integriert haben.
Ich hab mal nachgesehen wie das beim in der Industrie eingesetzten
Profinet IO gemacht wird. Das setzt zwar direkt auf der MAC Ebene auf,
aber ist demnach wie auch UDP paketorientiert.
Dort gibt es ein festes Aktualisierungsraster z.B. einer
Ausgabebaugruppe von 1 ms. Der Teilnehmer akzeptiert bis zu drei
Aktualisierungszyklen ohne Daten erhalten zu haben, danach geht er in
Fehlerzustand und setzt seine Ausgänge in einen sicheren Zustand.
Daraus folgt, dass bei Profinet einzelne Datenpakete unter Umständen
einfach unter den Tisch fallen. Obwohl ich das schon eingesetzt habe war
mir das bisher gar nicht klar. So würde meine UDP-Lösung dann (bis auf
den Fehlerzustand) auch funktionieren.
Bei Profibus (auch wenn das mit Profinet nicht unbedingt vergleichbar
ist, Token-Passing vs. CSMA) war das anders. Dort gab es ein Retry Limit
was im Normalfall in einem Netz ohne Repeater oder Ringstrukturen auf 1
steht. D.h. ein Telegramm wird auf jeden Fall zugestellt. Wenn nicht,
dann geht der Teilnehmer auf Fehler.
Es läuft letztlich auf die Frage hinaus, ob man im Steuerkanal mit den
Nebeneffekten von TCP leben kann, oder auf Basis von IP oder UDP einen
eigenes der Anwendung angepasstes Protokoll zur Sicherstellung der
Übertragung kritischer Informationen drauf setzt.
Man vergisst angesichts der Dominanz von TCP und UDP leicht, dass es
daneben noch einen ziemlichen Rattenschwanz anderer Transport Layer
Protokolle gibt. Man ist mit solchen Problemen selten der Erste. Nur
kann man nicht unbedingt drauf wetten, dass die im TCP/IP Stack schon
implementiert sind.
Anmerkung zur Paketgröße von Udp als auch Tcp-Paketen: ohne besondere
Optionen sind nur max. 1.5kByte Pakete zu empfangen und zu senden.
Zusätzlich ist der bereits erwähnte Umstand zu beachten dein
Betriebssystem (bzw sein Stack) packt seine Ethernetdaten direkt
hintereinander in seinen Puffer so das es nicht ohne weitere
Codierung/Makierung der Daten möglich ist diese einzelnen Paketen
zuzuweisen!
Trundle Trollkönig schrieb:> Anmerkung zur Paketgröße von Udp als auch Tcp-Paketen: ohne besondere> Optionen sind nur max. 1.5kByte Pakete zu empfangen und zu senden.
Das ist Sache des Network Layers (Ethernet). In TCP hat man es mit einem
Stream zu tun, daher ist die Paketgrösse wenig relevant.
In IP sind Pakete möglich, die grösser als ein Ethernet Frame sind,
somit gilt das auch für UDP. Weil sie ggf. fragmentiert werden.
> Betriebssystem (bzw sein Stack) packt seine Ethernetdaten direkt> hintereinander in seinen Puffer so das es nicht ohne weitere> Codierung/Makierung der Daten möglich ist diese einzelnen Paketen> zuzuweisen!
Das gilt für TCP. UDP Pakete bleiben erhalten.
ich hatte das vom TO so verstanden, das er immer ein Paket, verpackt in
nur einem Ethernetpaket (1 Frame = 1 Ethernetpaket zumindest kenn ich
das so), mit gleicher Payloaddatenstruktur, alle was weiß ich wieviel ms
versenden möchte und davon die aktuellsten Daten dann weiterverarbeiten
möchte. Dazu wäre es nötig die nicht mehr erkenntlich Paketstruktur im
tcp-stack, falls er Tcp-Protokoll verwendet, durch selbst implementierte
Markierungen des Payloads wieder herzustellen. Und wenn es nur 1
Ethernetpaket sein soll ist er nunmal an die maximale Ethernetpaketgröße
gebunden. Aber ich glaube mit vlan-tag kann man auch mehr als 1.5k
verschicken.
Habe ich das richtig verstanden?
1.2 ...
1.3 Der Client sendet die Zustände der Ausgänge mit einem Zeitstempel an
den PC.
2.1 Der Server, PC, berechnet anhand der empfangenen Zustände der
Ausgänge die neuen Zustände der Eingänge und schickt das Ergebnis an den
Client zurück.
2.2 Nebenbei wird mittels dem UDK ein Spiel (Anlage) ausgeführt, das auf
dem PC-Monitor dargestellt wird.
1.1 Der Client empfängt die neuen Zustände der Eingänge.
1.2 Der Client bzw. die SPS arbeitet den nächsten Zyklus ab.
1.3 Der Client sendet die Zustände der Ausgänge mit einem Zeitstempel an
den PC.
2.1 ...
Hi,
damit man sich mal was darunter vorstellen kann, gibts hier es ein Video
was mit der bisherigen Version (Kommunikation lokal) umgesetzt wurde:
http://www.youtube.com/watch?v=KzuPgLJ88UU
Das "Spiel" (Simulation ist der passendere Ausdruck) bildet sozusagen
die Realität ab. Die roten Linien stellen Lichtschranken dar, die SPS
steuert in dem Fall einfach ein paar Motoren an.
@mar IO:
Beide Programme sind in keiner Weise synchronisiert.
Der Zyklus der Simulation sieht so aus:
1. Simulation liest die Befehle aus der SPS (z.B. Motor an oder aus)
2. Berechnung der Physik
3. Zurückschreiben vom Signalen an die SPS (z.B. Lichtschranke belegt)
4. Rendern des Bildes
Die SPS hat im Normalfall ebenfalls eine zyklischen oder freilaufenden
Task. Liest die Eingänge ein (z.B. Lichtschranke belegt) und startet
daraufhin einen Motor.
Bezüglich UDP schreibe ich mir erstmal ein kleines Testprogramm um zu
sehen wie sich die Kommunikation da überhaupt verhält. Bezüglich
Paketgröße findet man widersprüchliche Angaben im Netz. Wenn die Daten
über eine DSL Leitung gehen wird ja auf jeden Fall auf MTU Größe
fragmentiert. Aber im LAN dürfte das doch nicht der Fall sein.
Thomas schrieb:> Bezüglich UDP schreibe ich mir erstmal ein kleines Testprogramm um zu> sehen wie sich die Kommunikation da überhaupt verhält. Bezüglich> Paketgröße findet man widersprüchliche Angaben im Netz. Wenn die Daten> über eine DSL Leitung gehen wird ja auf jeden Fall auf MTU Größe> fragmentiert. Aber im LAN dürfte das doch nicht der Fall sein.
Es gibt immer eine MTU. Im Ethernet ist die 1500, beim DSL leicht
darunter. Das bedeutet aber nicht, dass UDP Pakete darauf limitiert sein
müssen. Allerdings müssen IPv4-Stacks nicht mehr als 576 Bytes
reassemblieren können, wobei dieser Wert aber allenfalls bei
Zwergsystemen zu finden ist, nicht bei PCs.
Thomas schrieb:> Wenn die Daten> über eine DSL Leitung gehen wird ja auf jeden Fall auf MTU Größe> fragmentiert. Aber im LAN dürfte das doch nicht der Fall sein.
Bei Ethernet gibt es eine maximale Paketgröße. Mittels Jumbo-Frames kann
man das im lokalen Netz noch steigern. Das ist nützliche wenn man große
Menge an Daten über Netzwerk verschiebt, da man mehr Nutzdaten pro
Sekunde übertragen kann.
Im allgemeinen Interessiert die MTU nicht, da der UDP-Stack selber seine
Pakete entsprechend aufteilt.
mar IO schrieb:> Mittels Jumbo-Frames kann> man das im lokalen Netz noch steigern.
Im Prinzip ist das zwar richtig, es wird hier jedoch eher zur Verwirrung
beitragen, als ihm wirklich helfen. So lange man noch mit normalem
Ethernet und TCP/IP kämpft, sollte man von Jumbo Frames die Finger
lassen. Danach besser auch.
Mit einem Python UDP Socket bekomme ich bis zu 65515 Bytes mit einem
sendto() geschickt.
In der Wireshark-Anzeige sieht man dann gesplittete Einzelpakete zu je
max. 1480 Bytes, angezeigt als "Fragmented IP protocol". Das Zerlegen
und zusammensetzen scheint also auf IP Layer abzulaufen.
Sieht doch eigentlich zuverlässig aus, die Datenmenge reicht mir dicke
aus.
Thomas schrieb:> Sieht doch eigentlich zuverlässig aus, die Datenmenge reicht mir dicke> aus.
'Zuverlässig' ist es eben bei UDP nicht. Wenn ein Frame kaputt ist ist
das ganze datagram weg. Kann im LAN funktionieren, muss aber nicht.
Wenn du über DSL/WAN übertragen willst musst du unterhalb der MTU
bleiben.
/uli
A. K. schrieb:> U.Hertlein schrieb:>> Wenn du über DSL/WAN übertragen willst musst du unterhalb der MTU>> bleiben.>> Weshalb?
Das würde mich auch interessieren, denn im allgemeinen interessiert die
MTU nicht und vor allem in diesem Fall!