Ich erwäge, von TCP auf UDP umzusteigen, bin aber unsicher, ob meine
Gedanken dazu korrekt sind.
Im Folgenden meine ich mit "Anwendung" meine Programme sowohl auf dem PC
als auch auf dem µC. Betriebsystem und IP Stack zähle ich nicht dazu.
Ich habe ein paar Basteleien hinter mir, wo selbst gebaute Elektronik
über Ethernet oder WLAN vom PC aus ferngesteuert wurde.
Da ich zuvor sehr viel Erfahrung mit seriellen Ports und Modems
gesammelt hatte, kam es mir "natürlich" vor, das TCP Protokoll zu
verwenden.
Allerdings ist mir bewusst geworden, dass TCP womöglich nicht die beste
Wahl war. Auf folgende Schwachpunkte bin ich gestoßen:
1) Der Verbindungsaufbau kostet (unnötige?) zusätzliche Zeit.
2) TCP scheint sicher zu stellen, dass Daten vollständig, korrekt und in
der richtigen Reihenfolge beim Empfänger ankommen. Aber im Störungsfall
kann die Übertragung für eine ungewisse Zeitspanne ins Stocken geraten
oder gar ganz abbrechen. Dass heisst, dass meine Anwendung auf Abbrüche
und Timneouts reagieren muss. Timeouts insbesondere dann, wenn meine
Anwendung kürzere Aussetzer (z.B. 10 Sekunden) schon als Fehler werten
soll, die beim IP Stack noch nicht zum Abbruch führen würden.
3) Wenn mein µC von vielen PC's zugleich angesprochen werden soll, muss
er entweder mehrere TCP Verbindungen zugleich verwalten (was Speicher
kostet) oder die Verbindungen müssen immer möglichst schnell wieder
getrennt werden und für andere Kommunikationspartner Platz zu machen.
Das wiederum würde den Netzwerk Traffix unnötig erhöhen und kommt mir
als "unsauber" wenn nicht gar unerwünscht vor.
4) Ich kann mich nicht drauf verlassen, dass ein zusammenhängender
String auch am Stück ankommt. Zum Beispiel ein Befehl wie "LIGHTS OFF"
könnte beim Empfänger zerstückelt in zwei Paketen ankommen, vor allem
wenn ich aus einer Linux oder Windows Anwendung heraus sende. Der
Empfänger braucht also Pufferspeicher, um die Empfangenen zeichen zu
sammeln, bis das Ende eines Befehl (z.B. anhand eines \n) erkannt wurde.
Da es bisher immer so war, gehe ich davon aus, dass meine Anwendungen
immer nur kleine Pakete von weit unter 1KB senden und empfangen. Der PC
sendet ein Paket als Befehl und erwartet ein Paket als Antwort. Oder der
µC sendet ungefragt Ereignisse zum PC.
Nun frage ich mich, ob ich künftig nicht besser auf UDP umsteige. Davon
verspreche ich mir ein paar Vorteile, aber ich weiß nicht, ob meine
Annahmen korrekt sind.
1) Verbindungsaufbau und Abbau entfallen.
2) Wenn ich ein Paket sende, kommt es irgendwann richtig und vollständig
beim Empfänger an, sofern die Übertragungsstrecke nicht defekt oder
massiv gestört ist.
3) Gesendete Pakete bis maximal 1KB werden nie zerstückelt.
4) Ich kann mit mehreren PC's annähernd gleichzeitig Kommandos zu einem
einzigen UDP Port auf einem µC senden.
5) Der µC kann erkennen, von welcher IP+Port ein Kommando kam, so weiß
er, wohin er die Antwort schicken muss.
6) Meine Anwendung muss also die empfangenen Daten nicht sammeln, denn
sie kommen immer am Stück als Paket an. 1 Paket = 1 Kommando oder
Antwort.
7) Der Einzige Fehler, auf den meine Anwendung reagieren muss, sind
Timeouts. Und selbst das kann unter Umständen entfallen, nämlich dann,
wenn die gesendeten Daten nicht wichtig waren oder ein
Wiederholmechanismus außerhalb der Anwendung existiert.
Dann wäre UDP ja viel einfacher zu verwenden, als TCP. Oder nicht?
Ich habe noch nie UDP verwendet. C/C++ kann es ganz sicher, wie sieht es
mit Java aus? Da kenne ich nur Streams.
Stefan U. schrieb:> Dann wäre UDP ja viel einfacher zu verwenden, als TCP. Oder nicht?
Ja, stimmt fast alles. Wenn UDP sich aber dann doch nicht speziell für
dein Thing eignet müßtest du wieder auf TCP gehen. (µC erkennt nicht auf
welchem Port UDP ankommt, sonder muß dort lauschen)
Stefan U. schrieb:> Nun frage ich mich, ob ich künftig nicht besser auf UDP umsteige.
Mach das. Die von Dir aufgeführten Schwachpunkte von TCP sind alle
zutreffend. Es ist halt für sichere Verbindungen gedacht, d.h. Du weißt
jederzeit, ob Dein Paket "drüben" ankam oder nicht.
> Davon> verspreche ich mir ein paar Vorteile, aber ich weiß nicht, ob meine> Annahmen korrekt sind.>> 1) Verbindungsaufbau und Abbau entfallen.
Korrekt.
> 2) Wenn ich ein Paket sende, kommt es irgendwann richtig und vollständig> beim Empfänger an, sofern die Übertragungsstrecke nicht defekt oder> massiv gestört ist.
Darauf würde ich mich nicht verlassen. Im Zweifel sollte Dein Gegenpart
schon eine Antwort über UDP schicken, um mitzuteilen, dass Deine
Nachricht angekommen ist.
Ich persönlich arbeite da gern mit einer Statemachine. Ich sende eine
Nachricht, warte aber nicht auf Antworten und lasse den µC was anderes
machen. Kommt dann irgendwann eine Antwort, dann vermerke ich die
dazugehörige Nachricht als erfolgreich versendet.
Aber dieses Vorgehen ist Geschmackssache. Es kommt immer drauf an, wie
wichtig es ist zu wissen, ob die Nachricht ankam oder nicht.
> 3) Gesendete Pakete bis maximal 1KB werden nie zerstückelt.
Falsch. Beachte die MTU:
https://de.wikipedia.org/wiki/Maximum_Transmission_Unit
Bei einem Wert von 576, wobei dann noch für IP-Header 20 Bytes, für UDP
zusätzlich 8 Bytes draufgehen, können auch noch weitere "IP options"
eingefügt werden. Daher würde ich nicht über 512 Bytes gehen.
576 ist der minimale Wert für die MTU, der möglich ist. Mit 512 Bytes
bist Du daher immer auf der sicheren Seite. Ohne "IP options" wäre die
theoretisch maximal mögliche Paketgröße, die nicht zerstückelt würde,
548.
Aber das ist alles theoretisch. Wenn Du UDP-Messages nur in Deinem
lokalen Netzwerk verschicken willst und nicht quer übers Internet, dann
gehen selbstverständlich auch höhere Werte. Bei Ethernet ist zum
Beispiel ein typischer Wert der MTU 1500. Ziehe dann noch Headergrößen
für IP und UDP ab und Du weisst, wie weit Du gehen kannst.
> 4) Ich kann mit mehreren PC's annähernd gleichzeitig Kommandos zu einem> einzigen UDP Port auf einem µC senden.
Kommt auf den IP-Stack auf dem µC an, ob er "annähernd gleichzeitige"
Nachrichten verarbeiten kann.
> 5) Der µC kann erkennen, von welcher IP+Port ein Kommando kam, so weiß> er, wohin er die Antwort schicken muss.
Ja, das ist aber eine Trivialität. Diese Info hast Du bei TCP genauso.
> 6) Meine Anwendung muss also die empfangenen Daten nicht sammeln, denn> sie kommen immer am Stück als Paket an. 1 Paket = 1 Kommando oder> Antwort.
Ich frage mich, warum Du bei solch simplen Kommandos wie "Licht an"
Kilobytes an Daten schicken willst....
Im wesentlichen ist das jedoch korrekt.
> 7) Der Einzige Fehler, auf den meine Anwendung reagieren muss, sind> Timeouts. Und selbst das kann unter Umständen entfallen, nämlich dann,> wenn die gesendeten Daten nicht wichtig waren oder ein> Wiederholmechanismus außerhalb der Anwendung existiert.
Jepp.
> Dann wäre UDP ja viel einfacher zu verwenden, als TCP. Oder nicht?
Natürlich. UDP ist viel einfacher. Vergleiche es mit der Post: Brief in
den Briefkasten und fertig. Umgekehrt regelmäßig den eigenen Briefkasten
leeren. Wenn zwischendurch der Briefbote verunglückt mit Deinem Brief:
Pech gehabt.
> Ich habe noch nie UDP verwendet. C/C++ kann es ganz sicher, wie sieht es> mit Java aus? Da kenne ich nur Streams.
Geht in Java selbstverständlich auch.
https://systembash.com/a-simple-java-udp-server-and-udp-client/
Google hätte Dir das aber auch im Bruchteil einer Sekunde beantworten
können.
Der entscheidende Punkt ist was damit uebertragen werden soll. Kann ich
es mir leisten ein paar Nachrichten zu verlieren, oder eben nicht.
Wenn ich ein File uebertrage muss es vollstaendig sein, sonst ist es
wertlos. Also TCP. Wenn man Sound oder Video uebertraegt, machen ein
paar fehlende Nachrichten nichts aus.
Anders herum, uebertraegt man Zustaende oder Zustandsaenderungen? Wenn
man Zustaende uebertraegt, zB Pegelmesser Daten, ist ein fehlendes
Packet egal. Wenn man hingegen Zustandswechsel uebertraegt, wie "Taste
wurde gedrueckt". geht etwas verloren.
Daher kann man die Antwort nicht pauschalisieren, und die Ansaetze nicht
gegeneinander ausspielen.
In einem gewissen hat man Spielraum. Wenn man aus Sicherheitsgruenden
einen Zustandswechsel nicht verpassen will, kann man ja Zustaende
uebertragen, und der Empfaenger muss dann selbst den Wechsel
herausfinden. Bedingt dann moeglicherweise eine hoehere Datenrate, resp
mehr Meldungen auf dem Bus, weil man Redundanz uebertraegt.
Da sind wir dann beim Thema, "hat das Protokol einen Zustand, oder
nicht".
Ich tendiere zu zustandsfreien Protokollen. Allerdings dann
Master-Slave.
Zustandsfrei bedeutet es gibt keinen impliziten Zustand, auf dem die
Meldungen aufbauen. Der Master fraegt dann die Slaves periodisch ab. Und
wird so ueber einen Zustand informiert, der Master uss sich nichts
merken, und kann neu gestartet werden, ohne Konsequenz. Wenn man die
Bandbreite hat...
Oder D. schrieb:> Wenn ich ein File uebertrage muss es vollstaendig sein, sonst ist es> wertlos. Also TCP.
Das ist nicht unbedingt zwingend, aber natürlich bequem. Die Prüfung auf
Vollständigkeit kann man auch auf der Anwendungsschicht machen.
Es gibt zum Beispiel diverse VPN-Tunnel, welche (auch aus
Geschwindigkeitsgründen) mit UDP arbeiten. Im Tunnel selbst ist aber
auch TCP möglich, obwohl es technisch über UDP transportiert wird.
Bruno schrieb:> Stefan U. schrieb:>> 3) Gesendete Pakete bis maximal 1KB werden nie zerstückelt.>> Unwahrscheinlich aber nicht garantiert!
Ach ja, und die Reihenfolge in der die Pakete ankommen ist auch nicht
garantiert.
Danke für Deine Anregungen. Ihr habt mir damit gut geholfen, meine
Gedanken zu sortieren.
> Was hast Du eigentlich vor?
Überlegen, ob es sich für mich lohnt, mich mit UDP zu beschäftigen. Ist
ja nur ein Hobby, aber ich habe auch Familie.
> aber Hauptsache IoT im Titel stehen :rolleyes:
Mir war nichts intelligenteres eingefallen.
> µC erkennt nicht auf welchem Port UDP ankommt, sonder muß dort lauschen
Ja, soweit ich das bei µIP gesehen habe, muss er auf einem bestimmten
Port lauschen. Das scheint mir aber kein Hindernis zu sein.
> Ich frage mich, warum Du bei solch simplen Kommandos wie "Licht an"> Kilobytes an Daten schicken willst....
Will ich ja gerade nicht. Die 1KB hatte ich genannt, weil mir kein
Anwendungsfall einfällt, wo ich mehrere KB am Stück senden würde.
> Wenn man hingegen Zustandswechsel uebertraegt, wie "Taste> wurde gedrueckt". geht etwas verloren.
Ja logisch.
Bisher hatte ich fast immer Befehle gesendet und auf Antwort gewartet.
Da würde ich dann ggf. den Befehl nochmal wiederholen. Bei TCP habe ich
bisher auch Wiederholungen vorgesehen, allerdings auf einer neuen
Verbindung (und daher Aufwändiger).
> Ich tendiere zu zustandsfreien Protokollen. Allerdings dann Master-Slave.
Ich auch. Ich bemerke nun, dass ich TCP regelrecht missbraucht habe -
das einfachere UDP wäre besser geeignet gewesen.
> Die Reihenfolge in der die Pakete ankommen ist auch nicht garantiert.
Heisst in der Praxis: Wenn ich "LICHT AN" sende und direkt danach "LICHT
AUS", könnte das Ergbnis sein, dass das Licht am Ende ungewollt an ist.
Man könnte Sequenznummern hinzufügen, so dass der Empfänger veraltete
Kommandos ignoriert. Wobei das ja wieder eine Funktion von TCP ist ...
Darüber denke ich nochmal nach.
Was mir erst durch die Diskussion so richtig bewusst geworden ist:
Eine TCP Verbindung ist kaum mit einer Modem Verbindung vergleichbar.
Beim Modem können gesendete Zeichen unterwegs verloren gehen, obwohl die
Verbindung noch besteht. Bei TCP ist das nicht der Fall. Das habe ich
nicht bedacht, deswegen habe ich meine TCP Anwendungen bsiher unnötig
kompliziert gemacht.
Der Wechsel zu UDP wird mir sicher sehr leicht fallen.
Die nicht garantierte Reihenfolge beim TCP hat etwas mit dem Routing zu
tun. Langdistanzverbindungen koennen theoretisch ueber verschiedene Wege
gehen, wenn einer der Wege verstopft ist. Sofern die Infrastruktur das
kann. Nennt sich loadbalancing am Router. Das Ganz ist allerdings fuer
zuhause uninteressant, denn diese Funktionalitaet ist schlicht nicht
vorhanden.
Und ja, das TCP arbeitet mit Sequenznummern. Deswegen ist es auch
leichter auszutricksen, resp zu blockieren. Denn der Empfaenger muss
alle Packete mit nicht in die Reihe passenden Sequenznummern buffern bis
sie an die Reihe kommen. Wenn ich also eine Meldung schicke mit
Sequenznummern 1,2,3,4,5,10, und dann abbreche, ist diese Verbindung
offen und blockiert, er wartet auf Packete 6,7,8,9. Wie lange weiss ich
nicht, ein Timeout. Wieviele gleichzeitigen Verbindungen pro Client
akzeptiert der Server ? 10, 100 ? Irgendwann ist das Memory voll.
Oder D. schrieb:> Denn der Empfaenger muss> alle Packete mit nicht in die Reihe passenden Sequenznummern buffern bis> sie an die Reihe kommen.
muss? Er kann sie auch einfach verwerfen und behaupten er hat sie nicht
bekommen. Dann muss der Client sie neu versenden.
Das ist viel mehr ein Frage vom Puffer im Client, dann er muss jedes
Paket noch speichern, wenn er keine Empfangsquittung hat.
UDP ist deutlich einfacher wenn alle Daten in eine Message reinpassen
und verlorene Messages das System nicht durcheinander bringen. Die
Messagegrösse ist OS abhänging und kann auch über mehrere Frames gehen,
aber das Limit wird hier uIP sein wenn du das verwenden willst. Im
heimischen Netz gehen auch keine Messages verloren, das passiert meiner
Erfahrung nach wenn ein Sender extrem schnell sendet und der Empfänger
nicht nachkommt wg. z.B. zuwenigen Buffern bei zu langsamer
Verarbeitung. Aber so CM3 MCUs mit NIC wie LPC1769 machen da locker 1 ms
Zyklus mit.
Beim uIP ist die UDP Implementierung nicht so toll. Schnell schon, da
passiert ja nicht viel. Aber ich wollte zB so ein recvfrom(), also auf
einem Port lauschen und von beliebiger Adresse empfangen und dem Sender
Antworten zurückschicken. Das konnte uIP nicht weil die Senderadresse
nicht gespcheichert wird. Da der Stack aber recht überschaubar ist lässt
sich sowas nachträglich einbauen. An der Stelle wollte ich mich immer
mal mit lwIP beschäftigen, das soll besser sein und die CM3 haben alle
genug Power dafür.
Jojo S. schrieb:> UDP ist deutlich einfacher wenn alle Daten in eine Message reinpassen> und verlorene Messages das System nicht durcheinander bringen. Die> Messagegrösse ist OS abhänging und kann auch über mehrere Frames gehen,> aber das Limit wird hier uIP sein wenn du das verwenden willst. Im> heimischen Netz gehen auch keine Messages verloren, das passiert meiner> Erfahrung nach wenn ein Sender extrem schnell sendet und der Empfänger> nicht nachkommt wg. z.B. zuwenigen Buffern bei zu langsamer> Verarbeitung. Aber so CM3 MCUs mit NIC wie LPC1769 machen da locker 1 ms> Zyklus mit
Na dann, fröhliches pfuschen.
> Beim uIP ist die UDP Implementierung nicht so toll
Ja habe ich auch schon bemerkt. Allerding traue ich mir zu, ein
minimalistisches UDP Protokoll selbst zu entwickeln.
ich geh sogar noch weiter, und wickel es über broadcast ab... ich sende
ein datenpäckl mit dem zustand den ich gerne am aktor xy sehen würde,
und dieser sendet mir den aktuellen status zurück wenn er den befehl
ausgeführt hat.
das hat den luxusvorteil, das alle zur steuerung gehörende geräte eine
statusänderung mitbekommen und ggf anzeigen können, und ich nicht nur
weiß, dass der befehl angekommen ist, sondern auch ausgeführt wurde.
so brauch man sich auch keine gedanken machen, wenn ein gerät mal eine
andere IP zugewiesen bekommt.
funktioniert logischer weise nur in lokalen netzwerken und mit kniffen
max. noch im VPN...
Steven M. schrieb:> das hat den luxusvorteil, das alle zur steuerung gehörende geräte eine> statusänderung mitbekommen
Wer garantiert das das alle mitbekommen?
IP auf SOCs scheint grundsätzlich Pfusch zu sein, selbst die ASICs und
FPGAs in den Monstern von Juniper und Cisco sind total pfuschig und
verbuggt.
Profi schrieb:> Steven M. schrieb:>> das hat den luxusvorteil, das alle zur steuerung gehörende geräte eine>> statusänderung mitbekommen>> Wer garantiert das das alle mitbekommen?>
Niemand, deswegen ist es ein luxusvorteil...
Wenn ein gerät es genau wissen will, weil eine entscheidung ansteht,
kann man den status des zielgerätes ja abfragen...
Bei einem außentemperaturfühler zB, der alle 5 minuten die temperatur
ins netzwerk brüllt, ist es unerheblich, ob alle anzeigen jede meldung
mitbekommen, oder nur jede zweite
Ein aktor der temperaturabhängig schalten muss, fragt die temp halt
explizit ab...
Steven M. schrieb:> Niemand, deswegen ist es ein luxusvorteil...> Wenn ein gerät es genau wissen will, weil eine entscheidung ansteht,> kann man den status des zielgerätes ja abfragen...>> Bei einem außentemperaturfühler zB, der alle 5 minuten die temperatur> ins netzwerk brüllt, ist es unerheblich, ob alle anzeigen jede meldung> mitbekommen, oder nur jede zweite>> Ein aktor der temperaturabhängig schalten muss, fragt die temp halt> explizit ab...
Geile Sematik.
Bruno schrieb:> Stefan U. schrieb:>> 3) Gesendete Pakete bis maximal 1KB werden nie zerstückelt.>> Unwahrscheinlich aber nicht garantiert!
UDP sendet Datagramme. Diese können bis knapp 64k lang sein. Und sie
werden dem Anwederprogramm als ganzes geliefert. Immer! Das hat nichts
mit den Ethernetframes zu tun. Ist das Datagramm kürzer als eine MTU
wird es auch als ganzes in einen Ethernetframe gepackt, es kann ja
keinen angefangenen Frame geben, in dem noch Platz für neue Daten ist.
MfG Klaus
Klaus schrieb:> UDP sendet Datagramme. Diese können bis knapp 64k lang sein. Und sie> werden dem Anwederprogramm als ganzes geliefert. Immer! Das hat nichts> mit den Ethernetframes zu tun. Ist das Datagramm kürzer als eine MTU> wird es auch als ganzes in einen Ethernetframe gepackt, es kann ja> keinen angefangenen Frame geben, in dem noch Platz für neue Daten ist.
Fragmentiertes UDP wird aufwendiger und glaube nicht das die üblichen
IP-Stacks für damit klarkommen.
Aber die Idee ist gut, man könnte die Dinger mit unvollständigen
Fragmenten beschießen, mal sehen wie lange die damit klarkommen.
Es gibt keine enfache Daumenregel. Mal ist TCP sinnvoll, mal UDP. Die
Art der Kommunikation einer Anwendung bestimmt, was sinnvoller ist. So
sollte man auch berücksichtigen, inwieweit höhere Layer der
Kommunikation ebenfalls Retries durchführen - das kann beispielsweise
passieren, wenn man Anwendungen von anderen Übertragungsarten auf TCP/IP
portiert.
A. K. schrieb:> Es gibt keine enfache Daumenregel. Mal ist TCP sinnvoll, mal UDP.
Genau so ist das. Deswegen gibt es ja überhaupt diese zwei Protokolle,
denn wenn eins davon für alle Zwecke das geeignetste wäre, bräuchte es
ja auch nur dieses eine zu geben und das Problem der Auswahl würde sich
erst garnicht stellen...