Ich betreibe einige uC, welche auf einem RTOS laufen und dort auf einen integrierten Ethernet Stack zugreifen können.
Nun möchte ich eine Fremdapplikation integrieren, welche mit einer App arbeitet. Durch auslösen eines Knopfes auf der App, wird eine Nachricht an deren Server gesendet, welche diese Nachricht an meinen Server weiterleitet. Hierzu habe ich ein eigenes Backend geschrieben und deren Protokoll integriert, dieser Teil läuft auch ohne Probleme.
Was mir noch Probleme bereitet, ist die Verbindung zwischen meinem eigenen Server und meinen uCs. Zuerst habe ich eine REST Schnittstelle implementiert und polle von den uCs zum Server.
Da die Reaktionszeit kurz sein soll, polle ich inzwischen mit noch 200ms Abstand. Dies führt aber dazu, dass sehr viel Traffic entsteht und die meiste Zeit nichts zu melden ist.
Meine uC sind entweder über LAN angebunden, oder über einen SIM Karten Router. Besonders bei den SIM Karten ist der hohe Traffic ärgerlich, da ich hohe Kosten trage.
Welche Möglichkeit gibt es, um die Kommunikation umzudrehen? Meine uC besitzen über keine feste IP, noch sind sie von aussen zugänglich, da meist hinter einem Router.
Ich suche eine datensparende Lösung, um Benachrichtigungen meines Servers schnell mitzubekommen und die auf einem RTOS oder Barebone laufen.
Da die Reaktionszeit kurz sein soll, polle ich inzwischen mit noch 200ms
Abstand. Dies führt aber dazu, dass sehr viel Traffic entsteht und die
meiste Zeit nichts zu melden ist.
Verzögere Server-seitig die Antwort so lange, bis etwas "zu melden" ist oder der Client die Verbindung von sich aus wieder trennt.
Ich suche eine datensparende Lösung
Sparsam wären UDP Pakete von der Quelle zum Ziel, dafür muss das Ziel einen entsprechenden Listener laufen lassen.
Da muss doch keiner was verzögern. Eine stinknormale simple TCP Verbindung bleibt offen bis zum Sankt Nimmerleinstag und ist bidirektional, beide Gegner können nach belieben senden.
Eine stinknormale simple TCP
Verbindung bleibt offen bis zum Sankt Nimmerleinstag
CGNAT-Gateways (die ihm in den meisten Mobilfunknetzen begegnen werden) haben oft geizige Timeouts, man sollte schon alle paar Minuten Keepalives schicken.
Kommt drauf an, ob es eine Hobbybastelei ist, oder jahrelang unauffällig störungsfrei laufen soll.
Soll es auch die unzähligen Probleme behandeln, die alle paar Jahre mal auftreten? Und sollen alte Geräte mit neuen, erweiterten Servern zusammen arbeiten?
Irgend etwas, bei dem man ab und zu den Reset-Knopf drücken muss, bekommt man selbst zustande. Wenn es unauffällig und zuverlässig werden soll, kommst du wohl mit einem ausgereiften Konzept wie MQTT besser weg.
Da hab ich schon gehört, dass die Zeit zwischen Server und Endgerät schon relativ lange sein kann. Lange ist in meinem Fall alles was über eine Sekunde lang dauert. Hast du eine Zeitangabe, womit man etwa rechnen muss?
Verzögere Server-seitig die Antwort so lange, bis etwas "zu melden" ist
oder der Client die Verbindung von sich aus wieder trennt.
Das habe ich mir auch schon gedacht, kenne mich aber mit den Netzwerkprotokollen nicht genug aus. Wenn ich nun ein GET Request an das Backend mache, kann dann das Backend diesen Request auch erst z.B. morgen beantworten? Und so lange bleibt die Verbindung bestehen?
Merke ich vom uC aus, wenn die Verbindung abbricht und ich nichts mehr vom Server erwarten kann?
Eine stinknormale simple TCP
Verbindung bleibt offen bis zum Sankt Nimmerleinstag
CGNAT-Gateways (die ihm in den meisten Mobilfunknetzen begegnen werden)
haben oft geizige Timeouts, man sollte schon alle paar Minuten
Keepalives schicken.
Alle paar Minuten ein Keepalive senden sollte kein Problem sein, von mir aus auch 1 mal pro Minute.
Nur steh ich irgendwie auf dem Schlauch, wie ich eine TCP Verbindung aufmache. Bin ich da mit https schon zu weit weg? Oder ist das eine Art der https Verbindung?
Kommt drauf an, ob es eine Hobbybastelei ist, oder jahrelang unauffällig
störungsfrei laufen soll.
Soll es auch die unzähligen Probleme behandeln, die alle paar Jahre mal
auftreten? Und sollen alte Geräte mit neuen, erweiterten Servern
zusammen arbeiten?
Es soll jahrelang arbeiten können, wobei die Firmware immer updatebar bleibt. Es ist jeweils nur ein Server der verschiedene Devices abhandeln soll (>1000 mit der Zeit). Es ist keine Hobbybastelei.
Wenn ich nun ein GET Request ... erst z.B. morgen beantworten?
Reiner Zufall. Das Protokoll ist halt für Browser konzipiert, an denen ein Mensch sitzt. Kann jede Library machen, wie sie will.
Merke ich vom uC aus, wenn die Verbindung abbricht
Manchmal. Kann auch sein, du bekommst nur Fehlermeldungen, wenn das Senden nicht klappt. Nicht aber wenn dein Request ankommt, aber die andere Seite später nicht mehr antworten kann.
Nur steh ich irgendwie auf dem Schlauch
Solltest vielleicht erst mal ein Leerbuch für das Schichtenmodell durcharbeiten. Welche Aufgaben IP, TCP, HTTP und HTTPS haben.
Es soll jahrelang arbeiten können
Dann solltest du erst mal ein Tutorial durcharbeiten, das erklärt, warum Protokolle wie MQTT so aufwendig sind und warum es erfahrene Entwicklter mehrere Versionen brauchen, bis alles rund läuft.
Solltest vielleicht erst mal ein Leerbuch für das Schichtenmodell
durcharbeiten. Welche Aufgaben IP, TCP, HTTP und HTTPS haben.
Hast du eine Empfehlung? Das fehlende Wissen in diesem Bereich ist tatsächlich etwas, was immer wieder zurückfällt. Solange es im Firmwarebereich bleibt oder im Backend habe ich das gelernt, aber die Verbindung dazwischen komischerweise nie.
Da hab ich schon gehört, dass die Zeit zwischen Server und Endgerät
schon relativ lange sein kann. Lange ist in meinem Fall alles was über
eine Sekunde lang dauert. Hast du eine Zeitangabe, womit man etwa
rechnen muss?
Eine Sekunde ist sehr lang. Kommt natürlich auf den Payload und das Netzwerk an.
Das habe ich mir auch schon gedacht, kenne mich aber mit den
Netzwerkprotokollen nicht genug aus. Wenn ich nun ein GET Request an das
Backend mache, kann dann das Backend diesen Request auch erst z.B.
morgen beantworten?
Jein. Eine Minute geht auf jeden Fall. Mehr Verzögerung hängt von den Netzwerk-Komponenten ab. Bei uns auf der Arbeit trennt die Firewall alles, was 30 Minuten lang inaktiv ist. Aber ein Verbindungsaufbau alle 30 Minuten ist doch gut. besser als einer alle 200 ms.
Der Client kann Verbindungsverlust einfach eine neue aufbauen.
Oder der Server antwortet nach ein Paar Minuten "nix los", um die Trennung durch Firewall (oder andere Komponenten) zu verhindern. Allerdings muss der Client trotzdem fähig sein, bei Bedarf eine neue Verbindung aufzubauen. Ich würde mich nie darauf verlassen, dass eine einmal geöffnete Verbindung für immer verbunden bleibt.
Wenn ich nun ein GET Request an das
Backend mache, kann dann das Backend diesen Request auch erst z.B.
morgen beantworten? Und so lange bleibt die Verbindung bestehen?
Grundsätzlich ja, aber wenn solange gar nichts über die Leitung kommt, wird vermutlich irgendwo ein Timeout zuschlagen; das willst Du prinzipiell ja auch um zu erkennen, ob die Gegenstelle (und alle Geräte die dazwischen liegen) überhaupt noch lebt.
Aber Du kannst ja erstmal einen Teil der Antwort senden, z.B. die Header und anschließend in regelmäßigen Abständen halt ein einzelnes Leerzeichen, Zeilenvorschub o.ä. (die haben im Body einer http-Antwort normal eh keine Signifikanz) als keep-alive und wenns tatsächlich was zu melden gibt, den kompletten restlichen Body; sollte die Verbindung irgendwann mal mit einem Fehler abbrechen, dann startest Du einfach einen neuen Get-Request, ebenso wenn Du eine komplette Antwort erhalten hast.
Falls Du Deine http-Empfangsroutine am µC nicht so modifizieren kannst, daß empfangene keep-alive Zeichen gar nicht erst im Empfangspuffer landen, dann mußt Du die Verbindung außerdem rechtzeitig mit einer Leermeldung abschließen, bevor dem µC der Speicher knapp wird.
Wie oft Du die keep-alives senden mußt, insbesondere über Mobilfunk-Verbindungen, kannst Du ja testen, einfach mit ein paar Sekunden beginnen und dann steigern bis es irgendwann nicht mehr klappt, dann nimmst Du den letzten Wert mit dems noch funktioniert hat. Mach die Intervalle aber nicht zu groß, damit Deine Clients auch zeitnah mitbekommen, wenn der Server doch mal einen unkontrollierten Neustart macht.
Merke ich vom uC aus, wenn die Verbindung abbricht und ich nichts mehr
vom Server erwarten kann?
Normalerweise ja. Die Trennung wird in beide Richtungen durch ein RST Paket signalisiert.
Allerdings kann es bei technischen Störungen auch passieren, dass eine offene Verbindung unbemerkt verloren geht ohne dass das abschließende RST Paket übertragen werden kann.
Derjenige, der danach etwa sendet, erkennt dies in Form eines Timeouts (typisch nach 60 Sekunden), weil er keine Bestätigung empfängt. Das führt zur Trennung des TCP Sockets durch den IP Stack. Die andere Seite, die passiv auf Daten wartet, merkt den Verbindungsverlust nicht. Deswegen ist es klug, dort auf Applikations-Ebene einen Receive-Timeout zu implementieren.
Informiere dich mal über UDP, das könnte in deinem Fall einfacher sein, weil es ohne Verbindungen arbeitet. UDP kann man mit Postkarten vergleichen. Man schickt sie einfach ab, und meistens kommen sie zeitnah an.
Noch'ne Frage: warum nimmt Du eigentlich eine App, die eine Hersteller-Cloud braucht, welche Vorteile hat das für Dich? Wenn der hersteller nicht mehr mag, ist es aus.
Merke ich vom uC aus, wenn die Verbindung abbricht und ich nichts mehr
vom Server erwarten kann?
Häufig, aber nicht zwingend.
In deiner speziellen Situation hast du zwischen µC und Server ja noch einen Mobilfunkprovider mit Carrier-Grade-NAT. Wenn da beim CGNAT-Gateway deine Verbindung aus der Tabelle rausfällt (d.h. die Übersetzung der IP-Adresse), dann können beide Endpunkte nicht mehr miteinander reden. Und dafür gibt es weder eine vorgesehene Signalisierung des Gateways zu den Endpunkten noch würde danach ein RST-Package duchkommen können falls der Server da was merken würde.
Da hilft also nur einen Request vom µC zum Server zu senden und bei ausbleibender Auntwort die Verbindung neu aufzubauen. Bei CGNAT würde ich so etwas mindestens einmal pro Minute machen, aber …
Du musst dir also im Sinne von Real-Time-Anwendungen die Frage stellen, welche Reaktionszeit auf Nachrichten Server->µC maximal erlaubt ist. Und dann musst du z.B. MQTT-Pings innerhalb der existierenden Verbindung mit einem Intervall senden, so dass Intervall+Timeout+Neuaufbau unter dieser maximalen Reaktionszeit bleibt. Natürlich nur falls du wirklich harte Anforderungen hast. Wenn ein "in 99.9% der Fälle geht es gut" ausreicht, dann tut es auch ein seltenerer Ping. Aber im Worst-Case merkst du eben erst durch die ausbleibende Antwort (oder eine Fehlermeldung wenn der Request schon nicht gesendet werden kann) dass du gerade keine Nachrichten vom Server erhältst.
Du musst auch berücksichtigen, dass der Server die Nachrichten puffern muss (bei MQTT also mit persistent arbeiten), damit der µC dann nach dem Reconnect die ihm fehlenden Informationen erhält. Wenn es über einen Status hinausgeht (also z.B. auf 5 Messages müssen auch 5 Aktionen des µC erfolgen), dann muss dein µC dem Server auch die Verarbeitung jeder einzelnen Message bestätigen, denn sonst könnten da welche während so einer Unterbrechung der Verbindung unter den Tisch fallen (analog zu Interrupts beim µC, wenn da ein Timer z.B. dreimal überläuft bis der zugehörige Interrupt verarbeitet wird).
Für eine wirklich zuverlässige Kommunikation fällt da leider auch einiges an Traffic an. Da musst du dann bewerten, wieviel dir diese Sicherheit bzw. bestimmte Reaktionszeiten wert sind.
Informiere dich mal über UDP, das könnte in deinem Fall einfacher sein,
weil es ohne Verbindungen arbeitet. UDP kann man mit Postkarten
vergleichen. Man schickt sie einfach ab, und meistens kommen sie zeitnah
an.
Vergiss UDP wenn du du NAT dazwischen hast. Da musst du ja noch öfter als bei TCP keep-alive-Packages senden damit das Gaetway die (bei UDP nicht wirklich vohandene) "Verbindung" noch als existent betrachtet. Im Endeffekt hast du da in dieser Situation mehr Aufwand (und Traffic) als bei TCP.
Ja. Da sind die Timeouts zwar heutzutage wegen SIP auch oft länger (10-15 Minuten), aber man kann sich nicht darauf verlassen, dass das für alle Ports und Gegenstellen gilt.
Wobei mich noch interessieren würde ob es wirklich wichtig ist innerhalb einer Sekunde das Signal erfassen zu müssen oder ob es auch ausreicht einen genauen Timestamp zu schicken.
Ich kannte ZeroMQ bisher nicht. Der Vergleich hier würde mich eher
Richtung MQTT tendieren lassen.
Das bleibt Dir unbenommen. Aus meiner Sicht ist es allerdings so, daß MQTT eine zentrale Infrastrukturkomponente benötigt, nämlich den Broker. Solche Infrastrukturkomponenten und die Hardware, auf der sie laufen, haben leider die unangenehme Eigenschaft, bisweilen auszufallen, und wenn man bei MQTT keine Vorkehrungen dafür trifft, gehen dann Nachrichten verloren. Und wenn präventiv Vorkehrungen gegen Ausfälle getroffen werden, dann reden wir von einem hochverfügbaren Setup aus mindestens drei MQTT-Brokern, einer Floating IP und etwas zu deren Verwaltung, also so etwas wie Corosync/Pacemaker oder Keepalived und so etwas sie STONITH, und zusätzlich natürlich das kleine Einmaleins des Betriebes wichtiger Infrastrukturen: Monitoring, Alarming, und der ganze Rest, der zwingend dazu gehört. Dann ist so ein Setup leider nicht mehr so einfach, wie es auf den ersten Blick aussieht. Demgegenüber hat ZMQ IMHO einige Vorzüge, scheint mir, aber wie immer: YMMV, und Deine Wahl kann natürlich anders aussehen als meine.
Man darf dabei natürlich auch nicht vergessen, daß es bereits eine Vielzahl an Open- und ClosedSource-Produkten gibt, die bereits MQTT sprechen. Wer solche Produkte einsetzen will oder muß, wäre natürlich verrückt, wenn er nicht auf MQTT setzen würde. Aber wer selbst etwas implementiert, ist mit ZeroMQ gut bedient, und im Zweifelsfall lassen sich die beiden Technologien natürlich auch relativ gut und einfach miteinander kombinieren -- zum Preis weiterer Infrastrukturkomponenten allerdings, für die womöglich zumindest teilweise änhliches gilt wie das oben bereits erwähnte.
Wie kann denn eine Architektur wie oben vom TO beschrieben in ZeroMQ in Ausfallsicher aussehen?
Den Broker musst du doch bei ZeroMQ durch eine eigene Entwicklung
ersetzen, oder? Damit ist diese auch wieder zentral und muss eine entsprechende Verfügbarkeit haben.
Wie kann denn eine Architektur wie oben vom TO beschrieben in ZeroMQ in
Ausfallsicher aussehen?
Den Broker musst du doch bei ZeroMQ durch eine eigene Entwicklung
ersetzen, oder? Damit ist diese auch wieder zentral und muss eine
entsprechende Verfügbarkeit haben.
ZeroMQ puffert senderseitig, wenn sein Gegenüber ausgefallen ist. :-)