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
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.
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?
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.
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.
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.
Wenn du auf Daten verzichten kannst, weil sie fehlerhaft sind, dann kannst du auch UDP nehmen.
Frank M. schrieb: > Allerdings ist > diese ACK-Geschichte bei TCP ziemlich witzlos er wird das ACK im TCP Protokoll meinen.
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.
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.
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).
> 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.
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.
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
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.
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.
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) |
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.
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.
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.
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).
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
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
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.
Ui, das ist in der Tat minimalistisch und da lauern böse Fallstricke.
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
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!?
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.
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.
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.
> 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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.