Hallo zusammen, TLDR: In einer Applikation (x86 oder ARM Linux, nicht bare metal uC) muss ich innerhalb einer TCP/IP socket Verbindung auf einzelne Pakete in unter 10 Millisekunden eine Antwort zurück senden. Wie geht das mit der Socket API? Mir ist absolut bewusst, dass sockets eine Abstraktion auf TCP/IP sind. Bildlich gesprochen sind sockets für mich so etwas wie eine Röhre, in die man auf der einen Seite einen stream reingiesst und der trotz aller Unzulänglichkeiten der Verbindung auf der andere Seite wieder heraus kommt. Auf socket-Ebene merkt man von der Paketierung in einzelne TCP/IP Pakete, retransmission etc. gerade nichts. Das soll ja auch so sein. Jetzt möchte ich aber mit einem Gerät arbeiten, das zyklisch über eine TCP/IP Verbindung in Echtzeit (genauer unten) Antworten auf zyklische Anfragen benötigt. * Ich muss dem Gerät einen TCP/IP Socket Server bereit stellen. * Es verbindet sich zu mir per 3-way handshake (SYN, SYN-ACK, ACK). * Dann sendet es eine XML-Nachricht über diese TCP/IP Socket Verbindung als ASCII String. Die Nachricht hat eine variable Länge, passt aber immer in ein MTU von 1500. Somit wird nicht fragmentiert und eine Nachricht entspricht genau einem TCP/IP Paket. (Routing wird aktiv verhindert, indem die Pakete ein TTL von 1 haben) * Ich muss nun innerhalb von 10 Millisekunden eine Antwort über die socket Verbindung zurück senden. Sie ist wieder eine XML Nachricht und passt in genau ein TCP/IP Paket. In meiner Applikation (PC, Linux, C++, Python, was auch immer) bekomme ich über das Socket-Interface aber natürlich keine genaue Information, wann das Paket eingegangen ist. Es ist eher zufällig, wann der entsprechende TCP Stack des OS entscheidet, die Applikation zu informieren. Könnt ihr das Problem nachvollziehen und hättet Ideen oder Vorschläge, wie man das Problem elegant auf nicht-uC angeht? Auf einem uC würde ich natürlich direkt in der IRQ Routine das antriggern können ... Danke! PS: Die Entscheidung für XML über TPC/IP socket ist nicht von mir, sondern vom Hersteller des Gerätes vorgegeben. Das ist leider gesetzt, auch wenn ich es bisher noch nicht ideal erachte was die Technologie angeht.
TCP und XML sind für Echtzeit-Anwendungen mit kurzen Reaktionszeiten nicht sonderlich gut geeignet. Sascha S. schrieb: > In einer Applikation (x86 oder ARM Linux, nicht bare metal uC) > muss ich innerhalb einer TCP/IP socket Verbindung auf einzelne Pakete in > unter 10 Millisekunden eine Antwort zurück senden. TCP ist eigentlich Stream-orientiert und nicht Datagranm-orientiert. Das heißt, wie die von dir übergebenen Daten in Pakete aufgeteilt und übertragen werden, ist Sache des IP-Stacks. Du kannst dich lediglich darauf verlassen, dass alle gesendeten Bytes in der richtigen Reihenfolge wieder ankommen. > In meiner Applikation (PC, Linux, C++, Python, was auch immer) bekomme > ich über das Socket-Interface aber natürlich keine genaue Information, > wann das Paket eingegangen ist. Es ist eher zufällig, wann der > entsprechende TCP Stack des OS entscheidet, die Applikation zu > informieren. Ja, weil eben TCP. Siehe Nagle-Algorithmus (den man allerdings auch abschalten kann). Aber was genau brauchst du jetzt? Einen Zeitstempel der empfangenden Daten, oder dass sie schnellstmöglich in der Applikation ankommen? > PS: Die Entscheidung für XML über TPC/IP socket ist nicht von mir, > sondern vom Hersteller des Gerätes vorgegeben. Das ist leider gesetzt, > auch wenn ich es bisher noch nicht ideal erachte was die Technologie > angeht. Ist es auch nicht.
Es gibt ein paar Socketoptionen um Packete schneller zu handeln. Nodelay und cork: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_for_real_time/7/html/reference_guide/chap-sockets Ansonstnen kann man den Prozess noch auf eine CPU pinen, IRQ der NIC festnageln, realtimekernel, .... aber das wird wohl gar nicht notwendig sein und hilft auch nicht weiter wenn deine Verbindung schlecht/um den halben Erdball geht, dann werden die 10ms vermutlich öfters gerissen.
10ms sind dankbarerweise "relativ" lang für so einen PC. Mit etwas Glück und wenn dein System sonst nicht zu vollhängt kriegt das wsl eine ganz normale Applikation hin da zu reagieren... Je nachdem wie kritisch die Anwendung ist würde ich das einfach mal probieren wo deine Reaktionszeiten da landen.
Max D. schrieb: > 10ms sind dankbarerweise "relativ" lang für so einen PC. Ja, allerdings. Lesen und schreiben der Daten über den Socket ist in dem Fall nicht das Problem, sondern eben eher, dass man TCP so "verbiegen" muss, dass es nicht zu zu großen Verzögerungen im IP-Stack kommt und dass es etwas suboptimal ist, in einem (mehr oder weniger) Echtzeit-Kontext einen XML-Parser laufen zu lassen.
:
Bearbeitet durch User
Merci für alle Antworten schon einmal. Rolf M. schrieb: > Ist es auch nicht. Danke, dass Du meine Einschätzung teilst -) Rolf M. schrieb: > Aber was genau brauchst du jetzt? Einen Zeitstempel der empfangenden > Daten, oder dass sie schnellstmöglich in der Applikation ankommen? Ich benötige die Daten in der Applikation "so schnell wie möglich". Tatsächlich ist in den Daten bereits der Zeitstempel vom Absenden enthalten. Herbert B. schrieb: > aber das wird wohl gar nicht notwendig > sein und hilft auch nicht weiter wenn deine Verbindung schlecht/um den > halben Erdball geht, dann werden die 10ms vermutlich öfters gerissen. Die Verbindung ist direkt, per "kurzem" Ethernetkabel von Buchse Gerät zu meinem PC / RPi. Routen geht eh nicht wegen TTL = 1. Maximal kommt ein Switch dazwischen, zur not cut-through statt store-forward. Herbert B. schrieb: > Es gibt ein paar Socketoptionen um Packete schneller zu handeln. > Nodelay und cork: Das hört sich gut an, schaue ich mir an! Herbert B. schrieb: > Ansonstnen kann man den Prozess noch auf eine CPU pinen, IRQ der NIC > festnageln, realtimekernel, "CPU pinen" hört sich gut an. Jemand Erfahrung damit? "realtimekernel": Gerne auch: Gibt es da inzwischen etwas "fertiges" für ein RPi? Max D. schrieb: > 10ms sind dankbarerweise "relativ" lang für so einen PC. > Mit etwas Glück und wenn dein System sonst nicht zu vollhängt kriegt das > wsl eine ganz normale Applikation hin da zu reagieren... > Je nachdem wie kritisch die Anwendung ist würde ich das einfach mal > probieren wo deine Reaktionszeiten da landen. Ich habe es einmal probiert. Mit einer interpretierten Sprache (hust) klappt es nicht. Mit Wireshark bin ich da bei ca. 15 bis 20msec gelandet. Bevor ich auf C / C++ Rust whatever anfange, habe ich dann einmal angefangen über das eigentliche Problem nachzudenken. Ich darf tatsächlich 1% (Sample size 1000) der Antworten verspätet abliefern, daher eine "weiche" Echtzeitanforderung
Rolf M. schrieb: > dass es etwas suboptimal ist, in einem (mehr oder weniger) > Echtzeit-Kontext einen XML-Parser laufen zu lassen. Das muss ich auch noch genau evaluieren. Das XML ist relativ statisch (ggf. sogar sehr statisch, d.h. Struktur fix und "nur" Messwerte innerhalb der Struktur variieren). Dann würde ich das parsen vom XML auch alt-griechisch von Hand mit ein paar geschickten strtok hinbekommen.
Sascha S. schrieb: > Ich habe es einmal probiert. Mit einer interpretierten Sprache (hust) > klappt es nicht. Mit Wireshark bin ich da bei ca. 15 bis 20msec > gelandet. Wieviele XMLs schickt denn das Gerät? Kommt da ein Dauerstrom an XMLs oder ist das eine einmalige Aktion wo dann 1-? XMLs ankommen?
Herbert B. schrieb: > Wieviele XMLs schickt denn das Gerät? Kommt da ein Dauerstrom an XMLs > oder ist das eine einmalige Aktion wo dann 1-? XMLs ankommen? Das Gerät schickt immer das selbe XML alle 12 Millisekunden, in dem nur die Messwerte verändert sind (strings von floats mit fester Anzahl an Nachkommastellen). Das lässt sich denke ich händisch machen. Soweit ich es sehe, kann die Struktur des XML auch durch Konfiguration nicht verändert werden. Und wenn doch, ist das statisch, mit einem Neustart, verbunden. So dass auch der Server neu gestartet werden muss. Das kann also statisch, ggf. mit Codegenerator, erledigt werden IMHO. Herbert B. schrieb: > Sascha S. schrieb: >> Ich habe es einmal probiert. Mit einer interpretierten Sprache (hust) >> klappt es nicht. Mit Wireshark bin ich da bei ca. 15 bis 20msec >> gelandet. Tatsächlich klappt es auch zumindest testweise mit einer interpretierten Sprache mit `TCP_NODELAY`. Ich würde gerne aber noch das pinning und einen realtimekernel, z.B. auf einem RPi ausprobieren. Was schlagt ihr da vor?
Moin, Muss es denn unbedingt TCP sein? (RTP/)UDP ist fuer so'ne Faxen deutlich besser geeignet. Und solange das jetzt nur "ueber ein kurzes Kabel" muss, duerfte dann auch eh' nix verloren gehen, d.h. der ganze TCP Sermon: "Wie isset? Ja, danke und Selbst? Mussja..." sollte ueberfluessig sein. Gruss WK
Sascha S. schrieb: > Das muss ich auch noch genau evaluieren. Das XML ist relativ statisch > (ggf. sogar sehr statisch, d.h. Struktur fix und "nur" Messwerte > innerhalb der Struktur variieren). Dann würde ich das parsen vom XML > auch alt-griechisch von Hand mit ein paar geschickten strtok > hinbekommen. Deine Informationen sind leider etwas... spärlich, fürchte ich. Wie genau sehen die Anfragedaten aus, und wie genau die Antwortdaten? Brauchst Du die (alle?) Daten aus der Anfrage, um die Antwort zu erzeugen? Wann müssen die empfangenen Daten verarbeitet werden: sofort oder hat das Zeit? Wieviele Datenpakete empfängst Du in einem Zyklus? Worauf ich abziele, ist, daß Du Deine Daten vielleicht erst zwischenspeichern könntest, wenn das Deine verfügbaren Speichermedien nicht sprengt. Wenn Du Daten aus dem Requestpaket brauchst, um die Response zu erzeugen, könntest Du diese womöglich selektiv "ausschneiden" und den Rest des Paketes erst einmal einfach in irgendeine Datenstruktur, vermutlich eine Liste schreiben, oder in einen Redis-Server, oder... und das könnte eventuell auch asynchron gemacht werden (etwa einer leichtgewichtigen Goroutine), nachdem Deine Antwort schon gesendet worden ist. Je nach Speichermedium könnte auch sinnvoll sein, nicht jedes Paket sofort zu schreiben, sondern in Chunks: erst n Pakete sammeln und dann alle zusammen "in einem Rutsch" abspeichern, bei einem blockorientierten Gerät also warten, bis genug Daten für einen Block vorhanden sind. Nur so ein paar Ideen ins Blaue... HTH, YMMV.
Meiner Meinung nach ist das Design hier nicht ausgereift. Wer legt TCP/IP fest? Warum XML? Warum genau 10ms? Da hat doch jemand Parameter festgelegt, die in der realen Welt nicht funktionieren. Sprich mit den Leuten. Ich hätte UDP genommen, und auch mehr Zeit gegeben. Ja, man kann Tricksen, dass man es mit Kernel Parametern, Tricky Programmierung etc hinbekommt. Aber das ist nicht wartungsfreundlich, portabel, erweiterbar.
Sascha S. schrieb: > Das Gerät schickt immer das selbe XML alle 12 Millisekunden, in dem nur > die Messwerte verändert sind (strings von floats mit fester Anzahl an > Nachkommastellen). XML ist hier kein Flaschenhals da es ja in einee MTU reinpasst und simpel aufgebaut ist so dass man es ohne SAX-Parser, DOM-Geraffel auslesen kann. Dein Hauptproblem ist TCP, das einfach viel Overhead erzeugt. JEdes deiner Minipakete erwartet ein ACKN-Antwort, dann schickst du selber nochmal eine Antwort das auch wieder ein ACKN erwartet, bei solchen Minipaketen erzeugst du unnötig viel Overhead wo evt. deine Maschine aus dem Tritt kommt weil deren TCP-IP Stack schon unter kleiner Last wackelt,... Nix genaues weiss man ja nicht was du da einsetzt. Kannst ja noch einer Compilersprache herumexperimentieren da gewinnst du vielleicht beim Parsen noch etwas Zeit, mit CPU-Pininig, IRQ-Balancing abschalten, Realtimepatches,... würde ich es gar nicht erst versuchen, das bringt hier höchstwarhscheinlich nichts.
Sascha S. schrieb: > auch wenn ich es bisher noch nicht ideal erachte was die Technologie > angeht. Dergute W. schrieb: > Muss es denn unbedingt TCP sein? (RTP/)UDP ist fuer so'ne Faxen deutlich > besser geeignet. Und solange das jetzt nur "ueber ein kurzes Kabel" Da stimme ich Dir voll und ganz zu. Peter schrieb: > Da hat doch jemand Parameter festgelegt, die in der realen Welt nicht > funktionieren. Sprich mit den Leuten. Das ist leider hoffnungslos. Das Gerät ist von einem Konzern (> 1E9 EUR Umsatz) und das Produkt ist komplex und längst abgekündigt. An der Seite wird sich nichts ändern lassen. Die haben wahrscheinlich noch nicht einmal mehr die Quellen. Friss oder stirb ist die Devise dort leider. Sheeva P. schrieb: > Wann müssen die empfangenen Daten verarbeitet werden: sofort > oder hat das Zeit? Wieviele Datenpakete empfängst Du in einem Zyklus? Ich bekomme in einem Zyklus genau ein XML-Konstrukt in einem TCP-Paket, das ich "sofort" beantworten muss und die Antwort muss "sofort" (konkret <= 10ms nach Absenden) im Gerät als Antwort eingehen. Peter schrieb: > Ich hätte UDP genommen, [...] Ja, siehe oben. In einer etwas neueren Version (die wahrscheinlich inkompatibel für mein Gerät ist) ist UDP eine Option. Das muss ich aber noch prüfen. Am Ende ist es aber auch wieder der Netzwerkstack des OS, der nicht garantiert, dass die Applikation "sofort" das Paket bekommt. Peter schrieb: > [...] und auch mehr Zeit gegeben. Das ist tatsächlich nicht möglich, da meine Antworten auf die Nachrichten in einen harten Echtzeitprozess (mit RTOS, Regler, etc., Zykluszeit 10ms) im Gerät eingreifen. Somit muss man schon "zügig" da eine Antwort liefern. Das Parsen des XML ist gar nicht mein grösstes Problem. Da bin ich sicher, eine Variante zu finden, die schnell genug ist. Es ist auch eher ein String mit fester Struktur, der halt am Anfang, Ende und dazwischen das XML-Geraffel drin hat. Mein Kernproblem ist der TCP/IP Stack, der ggf. verzögert die eingehenden Pakete an meine Applikation liefert. Da hat TCP_NODELAY schon eine Verbesserung gebracht. Da möchte ich aber noch sehen, wie ich das verbessern kann, damit ich mehr Zeit habe, mir meine Antwort zu berechnen. Diese hängt nämlich von den eingehenden Daten ab. Effektiv schleift man über diese Schnittstelle eine externes Gerät in die Echtzeitregelkreise des Zielgerätes ein.
Herbert B. schrieb: > Kannst ja noch einer Compilersprache herumexperimentieren da gewinnst du > vielleicht beim Parsen noch etwas Zeit, Danke für Deine Einschätzung, ja da bin ich gerade dran. > mit CPU-Pininig, IRQ-Balancing > abschalten, Realtimepatches,... würde ich es gar nicht erst versuchen, > das bringt hier höchstwarhscheinlich nichts. Danke auch hier für Deine Einschätzung. Das wäre vermutlich ein rabbit hole, in dem ich verschwunden wäre. Das Design und Technologieentscheidung ist ja nicht von mir, sondern wie gesagt von dem Hersteller. Wenn man mit einem bare-metal embedded System mit Ethernet-Schnittstelle auf das Gerät zugreift, hat man Ende der 90er vielleicht gar nicht einen ganzen TCP/IP Stack implementiert, sondern ggf. schon fast hard-coded "SYN, SYN/ACK, ACK". Wenn man dann über die IRQ vom uC (oder gar externer Ethernet MAC) jedes Paket einzeln erhält, kann man die Daten eigentlich ganz bequem rechtzeitig abholen und beantworten. Und das ganze mit XML aufzublähen passt dann als Managemententscheidung zu Anfang der 2000er, damit man auch "innivotiv" ist. Man kann daraus nur lernen, wie man es besser nicht macht .-) und ein paar Tricks entwickeln, trotzdem damit zurecht zu kommen und das Ziel zu erreichen.
TCP bringt im Zweifel Verzögerungen im Minutenbereich. Was passiert eigentlich wenn der Sender sein Zeug nicht los wird, wie lange dauert es bis eine neue Verbindung versucht wird?
Wenn man die Zeiten und TCP nicht ändern kann: Ich spiele gerade mit einem STM32H743 mit Ethernet herum. Der Prozessor selber kann auch Ethnernet. Kommt ein Paket an, dann gibt es einen Interrupt, und man kann sofort das Paket analysieren, und irgendwas zurück schicken. Da ist dann kein Delay oder Taskwechsel dazwischen. STM liefert FreeRtos und einen LW IP-Stack mit. Geht jedoch auch ohne, man kann nackte Pakete schicken. Ist Bare-Metal Programmierung ohne OS. Muss man können/mögen.
Es gibt zwei Bremsen, einmal den Nagle Algorithmus der ja schon genannt wurde. Da wartet der Sender wenn nur wenig Daten zu Senden sind bis es lohnt. Das kann mit der Socket Option TCP_NODELAY beeinflusst werden. Dann gibt es noch Empfangsseitig ein delayed Ack. Hier kann der Empfänger mehrere bis zig ms warten bevor er ein Ack an den Sender zurückschickt. Das kann der Sender nicht beeinflussen und es hängt vom OS ab ob und wie lange ein Ack verzögert wird. Also von daher ein Ping Pong mit kleinen Anfragen/Antworten vermeiden.
Ist denn die Antwort abhängig vom Inhalt des gerade empfangenen Paketes? Ansonsten könnte man diese quasi "vorfertigen", damit sollte sich der Aufwand für die Antwort trotz XML in Grenzen halten ...
Hier, siehe Link, hat einer einen Ethercat-Master auf einem Raspi implementiert, vielleicht kannst du (TE) dir da ein paar Ideen holen. Ethercat nutzt nicht TCP sondern nackte Ethernet-Pakete, aber er hat anscheinend harte Echtzeit hinbekommen. http://www.simplerobot.net/2021/04/picat4-fast-prototyping-four-wheeled.html
Sascha S. schrieb: > TLDR: In einer Applikation (x86 oder ARM Linux, nicht bare metal uC) > muss ich innerhalb einer TCP/IP socket Verbindung auf einzelne Pakete in > unter 10 Millisekunden eine Antwort zurück senden. Wie geht das mit der > Socket API? Wurde ja schon diverses genannt. Aber 10ms sind jetzt wirklich nicht eine Herausforderung. Das Linux mit einem RT-Patch versehen und dann kannst du ja das Socket pollen. Besser auf UDP umsteigen. Oder wenn du ganz tief und hardware nah sein möchtest -> XDP Eventuell kannst du ja bei den Socket-Implementationen von Open62541 etwas abschauen
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.