Forum: Mikrocontroller und Digitale Elektronik Datenübertragung per TCP und UDP


von Matthias X. (aif93)


Lesenswert?

Hallo zusammen,

kurz die Ausgangsposition:
Ich soll Daten von einem Evaluationsboard (mit Freescale 
Microcontroller) an meinen Laptop per Ethernet senden und würde mich 
über eine fachliche Meinung von euch freuen. Ich bekomme live einen 
Datenstrom auf mein Board und diese Daten will ich dann sofort 
weiterleiten.
Aktuell sende ich die Daten per TCP von meinem Board zum Laptop: das 
Board ist der Server und auf meinem Rechner läuft ein Python Client der 
die Daten empfängt und verarbeitet.
Die Datenübertragung funktioniert auch ganz gut jedoch muss mein Server 
auf ein ACK vom Client warten (über Wire shark sehe ich, dass ich 200 ms 
auf das ACK warten muss).
Die erste Frage ist somit, ob es bei dieser Verbindung immer nötig ist, 
dass ich auf das ACK vom Client warten muss bevor der Server ein neues 
Paket sendet? In der Wartezeit "fülle" ich dann wieder meinen 
Ethernetsendepuffer mit den Livedaten.

Die zweite Frage ist, ob eine Verbindung per UDP dieses Problem lösen 
würde oder ob ich dann zu viele Fehler habe wenn Daten nicht?

Vielen Dank für eure Hilfe.

Matthias

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Matthias X. schrieb:
> Die erste Frage ist somit, ob es bei dieser Verbindung immer nötig ist,
> dass ich auf das ACK vom Client warten muss bevor der Server ein neues
> Paket sendet?

Nö, dann wäre die Übertragung ja unendlich langsam, das wären dann ja 
gerade mal 5 Pakete pro Sekunde.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Matthias X. schrieb:
> Die erste Frage ist somit, ob es bei dieser Verbindung immer nötig ist,
> dass ich auf das ACK vom Client warten muss bevor der Server ein neues
> Paket sendet?

Das kommt auf den Client an, ob er das so akzeptiert. Allerdings ist 
diese ACK-Geschichte bei TCP ziemlich witzlos, da die TCP-Schicht 
bereits sicherstellt, dass die Daten auch ausgeliefert werden. Kommen 
sie aus irgendeinem Grunde beim Client nicht an, bekommt der Server 
einen Fehler präsentiert.

> In der Wartezeit "fülle" ich dann wieder meinen
> Ethernetsendepuffer mit den Livedaten.

Nicht verkehrt.

>  Die zweite Frage ist, ob eine Verbindung per UDP dieses Problem lösen
> würde oder ob ich dann zu viele Fehler habe wenn Daten nicht?

"Verbindung per UDP" ist ein Widerspruch in sich:

TCP - verbindungsorientierte Kommunikation
UDP - verbindungslose Kommunikation

Oder meinst Du, Du stehst in dem Moment mit dem Empfänger "in 
Verbindung", wenn Du einen Brief in einen Briefkasten wirfst?

von Johannes S. (Gast)


Lesenswert?

Matthias X. schrieb:
> über Wire shark sehe ich, dass ich 200 ms
> auf das ACK warten muss

Dafür hat der Herr Nagle gesorgt:
https://de.wikipedia.org/wiki/Nagle-Algorithmus

bei UDP gibt es das nicht, dafür können Pakete verloren gehen. Bei einer 
Punkt zu Punkt Verbindung allerdings eher selten, nur wenn der Gegner 
keine Buffer mehr hat. Dafür müsste man dann selber eine Sicherung 
darüber bauen.

von Georg G. (df2au)


Lesenswert?

Matthias X. schrieb:
> Die erste Frage ist somit, ob es bei dieser Verbindung immer nötig ist,
> dass ich auf das ACK vom Client warten muss bevor der Server ein neues
> Paket sendet?

Da gilt Radio Eriwan: Es kommt darauf an. TCP kennt einen 
Fenstermechanismus, bei dem der Sender munter plappert und ab und an 
kommt ein Sammel-ACK. Der Nachteil dabei: Der Sender muss alle Frames 
weiter auf Abruf halten, bis er die Empfangsbestätigung bekommt. Hat 
dein Eval-Board so viel Speicher?


> Die zweite Frage ist, ob eine Verbindung per UDP dieses Problem lösen
> würde oder ob ich dann zu viele Fehler habe wenn Daten nicht?

Auch hier die gleiche Antwort: Es kommt darauf an. UDP hat immer 
Datenverluste. Wie hoch die Verluste sind, hängt von x Parametern ab. 
Wenn dein Auswerteprogramm damit leben kann: Prima, UDP ist einfacher, 
hat weniger Overhead.

von Stefan F. (Gast)


Lesenswert?

Das mit dem ACK delay ist eine Eigenart von Windows. Windows Programme 
können die Option TCP_NODELAY aktivieren, um dies zu verbessern.

https://aboutsimon.com/blog/2012/07/27/Python-TCP-socket-performance-tweak-on-Linux.html

UDP ist nicht betroffen, weil es kein ACK erwartet. Aber UDP Pakete 
können verloren gehen.

von Dirk B. (dirkb2)


Lesenswert?

Wenn du auf Daten verzichten kannst, weil sie fehlerhaft sind, dann 
kannst du auch UDP nehmen.

von Johannes S. (Gast)


Lesenswert?

Frank M. schrieb:
> Allerdings ist
> diese ACK-Geschichte bei TCP ziemlich witzlos

er wird das ACK im TCP Protokoll meinen.

von Johannes S. (Gast)


Lesenswert?

Stefan U. schrieb:
> Das mit dem ACK delay ist eine Eigenart von Windows.

Das ist ein nicht tot zu kriegendes Gerücht, der Nagle Algorithmus ist 
uralt und eine Empfehlung für TCP Implementierungen die u.a. Microsoft 
in Windows umgesetzt hat.

von Stefan F. (Gast)


Lesenswert?

Linux hat den Algorithmus auch, aber Linux erkennt dazu inkompatible 
Verbindungspartner und reduziert das Delay nach einer Weile automatisch 
auf wenige ms. Windows tut das nicht.

von Jim M. (turboj)


Lesenswert?

Matthias X. schrieb:
> Die erste Frage ist somit, ob es bei dieser Verbindung immer nötig ist,
> dass ich auf das ACK vom Client warten muss bevor der Server ein neues
> Paket sendet?

Nö, muss man bei TCP nicht - aber je nach verwendetem IP Stack müsste 
man eventuell viel umprogrammieren.

Besser ist dann der fiese Trick das völlig fertige TCP Paket einfach 2x 
zu senden - der Client antwortet in diesem Falle sofort mit ACK.

ACK Delay auszuschalten ist im Zeitalter des Internets und Gigabit eine 
richtig blöde Idee.  UDP über WLAN (Laptop!) wird lustig (Stichworte 
Retransmit und Packet loss).

von Stefan F. (Gast)


Lesenswert?

> ACK Delay auszuschalten ist im Zeitalter des Internets und Gigabit
> eine richtig blöde Idee.

Frühe konnte man das über einen Registry Eintrag machen. Jetzt nicht 
mehr (finde ich auch richtig so). Immerhin können Anwendungsprogramme 
diese Option noch für jede Verbindung einzeln einstellen.

Nur leider geht das in den mir bekannten Web Browsern nicht. Man müsste 
dort wohl den Quelltext ändern.

von Johannes S. (Gast)


Lesenswert?

Stefan U. schrieb:
> Linux hat den Algorithmus auch, aber Linux erkennt dazu inkompatible
> Verbindungspartner

Wenn der Gegner fix ist und man sich darauf verlassen möchte mag das ok 
sein, aber der Standard ist das delayed ACK. Man kann es mit TCP_NODELAY 
versuchen abzuschalten, aber soweit ich weiss ist es ist kein muss für 
den Gegner, wenn er nicht will oder kann darf er das ignorieren.

Mittlerweile gibt es noch ein TCP_QUICKACK und das OS kann 
Protokollabhängig das ACK schnellstmöglich schicken.

von (prx) A. K. (prx)


Lesenswert?

Das Problem entsteht, wenn man einfache TCP Stacks wie µIP einsetzt, die 
nur einen einzigen Ethernet-Frame puffern. Dann muss man den bestätigt 
bekommen bevor man den nächsten aufbauen kann. Und das dauert, da die 
üblichen Stacks erst sehr verspätet bestätigen.

Abhilfe: Jeden Frame zweimal direkt hintereinander senden. Dann glaubt 
der Stack des Partners, dass etwas schief lief, und bestätigt den 
zweiten sofort. Das braucht zwar doppelte Rate, aber die kriegt man dann 
auch.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Matthias X. schrieb:
> Die zweite Frage ist, ob eine Verbindung per UDP dieses Problem lösen
> würde

Im Prinzip ja. Aber nur im lokalen Netz.

> oder ob ich dann zu viele Fehler habe wenn Daten nicht?

Selten. Gelegentliche Fehler muss man trotzdem einrechnen. Ob man damit 
leben kann hängt von der Aufgabe ab. Benötigt man zwingend alle Daten, 
dann muss man auf UDP eine Übertragungswiederholung einbauen. Geht es 
aber beispielsweise um die Übertragung von Daten, bei denen die 
Aktualität wichtiger ist als die Vollständigkeit (z.B. Messwerte, 
Audio/Video), dann ignoriert man fehlende Daten einfach.

Über Internet ist UDP unabhängig davon für Übertragung grösserer Mengen 
allenfalls verwendbar, wenn man die Datenrate auf die wahrscheinlich 
übertragbare Rate drosselt. TCP macht das selbst, UDP nicht.

von Matthias X. (aif93)


Lesenswert?

Erstmal vielen Dank an alle!

A. K. schrieb:
> Das Problem entsteht, wenn man einfache TCP Stacks wie µIP einsetzt, die
> nur einen einzigen Ethernet-Frame puffern. Dann muss man den bestätigt
> bekommen bevor man den nächsten aufbauen kann. Und das dauert, da die
> üblichen Stacks erst sehr verspätet bestätigen.
>
> Abhilfe: Jeden Frame zweimal direkt hintereinander senden. Dann glaubt
> der Stack des Partners, dass etwas schief lief, und bestätigt den
> zweiten sofort. Das braucht zwar doppelte Rate, aber die kriegt man dann
> auch.


Ja ich verwende genau diesen Stack deshalb wohl das Problem. Danke für 
den Tipp ich werde das gleich mal ausprobieren.

Frank M. schrieb:
> Oder meinst Du, Du stehst in dem Moment mit dem Empfänger "in
> Verbindung", wenn Du einen Brief in einen Briefkasten wirfst?

War etwas umgangssprachlich formuliert aber du hast das schon richtig 
verstanden: "UDP Verbindung" im Sinne von ich sende Daten per UDP und 
mein Client empfängt diese Daten.

von Johannes S. (Gast)


Lesenswert?

Matthias X. schrieb:
> Ja ich verwende genau diesen Stack deshalb wohl das Problem.

Das Problem tritt aber da auch nur dann auf wenn man z.B. einen HTTP 
Server hat und der PC Browser als Client nicht beeinflusst werden kann 
wie er seinen Socket aufmacht.
Du schriebst aber Eingangs das du einen eigenen Python Client hast, da 
müsste man die Socket Option TCP_NODELAY setzen können und das Problem 
damit etwas sauberer lösen. Bin in Python nicht fit, aber die Python 
socket lib hat sowas hier:
1
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

von Jack (Gast)


Lesenswert?

Matthias X. schrieb:
> War etwas umgangssprachlich formuliert aber du hast das schon richtig
> verstanden: "UDP Verbindung" im Sinne von ich sende Daten per UDP und
> mein Client empfängt diese Daten.

Eine UDP "Verbindung" nennt man Session. Ähnlich wie eine TCP-Verbindung 
ist sie durch Source IP Adresse, Source UDP-Port, Destination IP Adresse 
und Destionation UDP-Port definiert. Zusätzlich manchmal durch die 
schwammige Bedingung, dass die UDP-Pakete einer Session einem 
"gemeinsamen Zweck" dienen.

Typischerweise verwendet eine UDP-Session beidseitig "connected" 
Sockets, also Socket, bei denen connect() aufgerufen wurde. Man kann 
UDP-Sessions auch ohne connect(), also mit "unconnected" Sockets 
aufbauen. Da connect() es bequemer macht (man gibt damit die Destination 
IP Adresse und den Destionation UDP-Port vor) ist connect() typisch.

von Barrex (Gast)


Lesenswert?

Bei "zeitkritischen Sachen" auf uC's mit z.B. uIP als Stack würde ich 
immer UDP nehmen, da das Timeout beim TCP-ACK laut Standard bis zu 500ms 
betragen kann. Allerdings würde ich dann selbst die Daten mit einer 
Checksumme und einem Lebenszähler absichern. Das geht dann trotzdem 
immer noch wesentlich schneller als TCP mit seinem langen ACK.

Aber wie das oben erwähnt wurde, bringt in der Regel nur in einem 
lokalen Netzwerk was. Denke aber mal, daß das genau hier gemeint ist. 
Mit zeitkritisch meine ich lediglich Sachen die flotter gehen müssen, 
damit war keine Echtzeit gemeint. Im Grundsatz sind TCP/IP o. UDP/IP 
nicht echtzeitfähig.

von Mikro 7. (mikro77)


Lesenswert?

In der engl. Wiki ist das Problem (siehe auch Johannes Beiträge) gut 
beschrieben:

[The Nagle] algorithm interacts badly with TCP delayed acknowledgments, 
a feature introduced into TCP at roughly the same time in the early 
1980s, but by a different group. With both algorithms enabled, 
applications that do two successive writes to a TCP connection, followed 
by a read that will not be fulfilled until after the data from the 
second write has reached the destination, experience a constant delay of 
up to 500 milliseconds, the "ACK delay". For this reason, TCP 
implementations usually provide applications with an interface to 
disable the Nagle algorithm. This is typically called the TCP_NODELAY 
option.

https://en.wikipedia.org/wiki/Nagle%27s_algorithm

Da du bereits mit Wireshark sniffst, siehst du ja, ob genau dies 
zutrifft.

von Mikro 7. (mikro77)


Lesenswert?

A. K. schrieb:
> Das Problem entsteht, wenn man einfache TCP Stacks wie µIP einsetzt, die
> nur einen einzigen Ethernet-Frame puffern. Dann muss man den bestätigt
> bekommen bevor man den nächsten aufbauen kann. Und das dauert, da die
> üblichen Stacks erst sehr verspätet bestätigen.

Dann sollte aber auch nur ein entsprechend kleines Window vereinbart 
werden, wie Daten gepuffert werden können. Wird das Ack denn tatsächlich 
auch delayed, wenn das Window bereits voll ist?

Oder meinst du das wörtlich, dass der zuletzt gesendete Ethernet Frame 
gepuffert wird (auch wenn bspw. nur ein Byte übertragen wurde) und für 
diesen Frame wird dann auf ein Ack gewartet?! Das wäre in der Tat ein 
Problem (und ich würde dann auch nicht mehr von einer TCP 
Implementierung sprechen, auch falls das rein protokolltechnisch noch ok 
sein könnte).

von Klaus (Gast)


Lesenswert?

Mikro 7. schrieb:
> Oder meinst du das wörtlich, dass der zuletzt gesendete Ethernet Frame
> gepuffert wird (auch wenn bspw. nur ein Byte übertragen wurde) und für
> diesen Frame wird dann auf ein Ack gewartet?!

Wie sonst sollte sichergestellt werden, daß der Frame auch richtig 
angekommen ist? Im Fehlerfall muß er ja noch mal gesendet werden, der 
Stack muß ihn also noch vorrätig haben.

MfG Klaus

von (prx) A. K. (prx)


Lesenswert?

Nicht ganz so wörtlich, denn dieser eine Puffer wird ja für den Empfang 
des Ack-Frames gebraucht. Weshalb die Anwendung einen ggf. zu 
wiederholenden Frame reproduzieren muss.

Dunkels Werk ist absolute Minimalistik. Da ist natürlich auch kein 
Socket-API dahinter. Mehr als ein Frame ist nicht vorgesehen. Die 
Anwendung schickt den Frame raus und wenn nach Timeout keine passende 
Bestätigung kommt, dann baut sie ihn nochmal und schickt ihn erneut. 
Mehr ist da nicht.

"In order to reduce memory usage, the TCP in uIP does not implement a 
sliding window for sending and receiving data. Incoming TCP segments are 
not buffered by uIP, but must be processed immediately by the 
application. Note that this does not prevent the application from 
buffering the data by itself. For outbound data, uIP cannot have more 
than one outstanding TCP segment per connection."

http://www.dunkels.com/adam/download/uip-doc-0.5.pdf

von (prx) A. K. (prx)


Lesenswert?

Dunkels war sich der Problematik bewusst und hatte einen optionalen Hack 
gebaut, der den Frame künstlich fragmentiert. Sollte das Ack Problem 
lösen. Hat bei mir aber nicht funktioniert.

Dem Trick mit den der direkten Wiederholung der Frames bin ich erst 
später bei einem Wiznet Chip begegnet. Diese Dinger haben TCP/IP intern. 
Da begegnete ich unter bestimmten Randbedingungen im LAN-Trace solchen 
Dopplern.

von Mikro 7. (mikro77)


Lesenswert?

Ui, das ist in der Tat minimalistisch und da lauern böse Fallstricke.

von (prx) A. K. (prx)


Lesenswert?

Mikro 7. schrieb:
> Ui, das ist in der Tat minimalistisch und da lauern böse Fallstricke.

Yep. Eine universelle Lösung streng nach RFCs ist das nicht.

Ich hatte damit mit dem ATmega32 einen Datenlogger gebaut, der 
einerseits ein paar simple Webseiten als Statusanzeige liefert, 
andererseits 0,5MB Logdaten. Mit TCP dauerten diese 0,5MB viele Minuten. 
Weshalb ich für Übertragung innerhalb vom LAN zusätzlich auch simples 
UDP verwende: Die Daten Frame für Frame mit einer Sequenznummer versehen 
und rausfeuern. Oft kommt es komplett an, wenn nicht, dann fordert die 
PC-Anwendung das eben nochmal an. Über Internet geht natürlich nur TCP.

: Bearbeitet durch User
von Mikro 7. (mikro77)


Lesenswert?

Er (Dunkels) hat seine Implementierung zumindest gut dokumentiert. Die 
Idee, die Buffer in die Applikation zu verlagern, ist nicht schlecht. In 
letzter Konsequenz sollte die Applikation dann auch die Window Size 
vorgegeben. Der Schritt zu einem "konformen" TCP/Stack sollte nicht mehr 
weit sein. Das Interface zur App ist natürlich entsprechend "speziell" 
(durch die notwendigen callbacks).

A. K. schrieb:
> Über Internet geht natürlich nur TCP.

Wieso? Gerade wenn man keinen TCP/IP Stack hat, bietet sich doch UDP mit 
einfachen Send/Ack Handshake an!?

von (prx) A. K. (prx)


Lesenswert?

Mikro 7. schrieb:
> Wieso? Gerade wenn man keinen TCP/IP Stack hat, bietet sich doch UDP mit
> einfachen Send/Ack Handshake an!?

Ich beschrieb hier was ich implementiert hatte. Nicht was ich hätte 
implementieren können. Ein AVR ist zwar kein Rennpferd, aber wenn der 
wie bei mir ungebremst eine Folge von UDP Frames ohne Quittung 
rausbläst, dann ist er schneller als mancher DSL Uplink.

von Matthias X. (aif93)


Lesenswert?

Barrex schrieb:
> Bei "zeitkritischen Sachen" auf uC's mit z.B. uIP als Stack würde ich
> immer UDP nehmen, da das Timeout beim TCP-ACK laut Standard bis zu 500ms
> betragen kann.

Das ganze soll später sowieso auf einem Linux-System laufen. Ich hoffe, 
dass ich dann nicht 200 ms auf ein ACK warten muss. Dann wäre mein 
Problem sowieso gelöst - ich muss zum Glück nicht echtzeitfähig sein.

von Matthias X. (aif93)


Lesenswert?

Mikro 7. schrieb:
> Wieso? Gerade wenn man keinen TCP/IP Stack hat, bietet sich doch UDP mit
> einfachen Send/Ack Handshake an!?

UDP ist bei meiner Version vom uIP Stack noch nicht implementiert 
deswegen war der erste Ansatz über TCP/IP. Die Vor- und Nachteile von 
TCP sind mir bekannt, weswegen für meinen Anwendungsfall TCP auch die 
bessere Lösung ist.

von Stefan F. (Gast)


Lesenswert?

> Dann sollte aber auch nur ein entsprechend kleines Window
> vereinbart werden

µIP sende diese Information ja auch korrekt nach Windows. Und µIP sendet 
das ACK auch immer schnell. Nur Windows geht trotzdem einfach davon aus, 
das die Gegenstelle eine größere Windows size hat.

> Dunkels war sich der Problematik bewusst und hatte einen optionalen Hack
> gebaut, der den Frame künstlich fragmentiert. Sollte das Ack Problem
> lösen. Hat bei mir aber nicht funktioniert.

Bei mir auch nicht. Und die Variante, das Frame 2x zu senden hat bei mir 
auch nicht funktioniert.

von Mikro 7. (mikro77)


Lesenswert?

Matthias X. schrieb:
> UDP ist bei meiner Version vom uIP Stack noch nicht implementiert
> deswegen war der erste Ansatz über TCP/IP.

UDP ohne TCP/IP Stack: Wenn man sowieso nur ein Send/Ack Protocol (ohne 
Window) fährt (also kein Packet Reorder) und die kleinste Packet Size 
ausreicht (ohne Gefahr von IP Fragmentation), dann muss man "lediglich" 
die UDP/IP Header kodieren/dekodieren + ggf. Prüfsumme.

(Edit: +Re-Send after Timeout/NAK +Duplicate-Bit)

> Die Vor- und Nachteile von
> TCP sind mir bekannt, weswegen für meinen Anwendungsfall TCP auch die
> bessere Lösung ist.

uIP bietet kein "echtes" TCP an. Weder aus Protokollsicht noch aus 
Applikationssicht.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.