Wie Maschinen kommunizieren - MQTT-Protokoll


In einem früheren Artikel haben wir uns mit dem Modbus-Protokoll befasst , dem De-facto-Industriestandard für M2M- Interaktion. MQTT wurde 1979 entwickelt und weist eine Reihe bedeutender Nachteile auf, die MQTT löst.

Das MQTT-Protokoll ist noch recht jung (erst 2016 standardisiert), hat es jedoch bereits geschafft, in der Industrie und im Internet der Dinge weit verbreitet zu sein. Es wurde speziell entwickelt, um so kompakt wie möglich für instabile Internetkanäle und Geräte mit geringem Stromverbrauch zu sein, und ermöglicht Ihnen die garantierte Zustellung von Nachrichten bei Paketverlust und -trennung.

Hauptmerkmale des MQTT-Protokolls:

  • Kompakt und leicht - minimaler Datenübertragungsaufwand, um Datenverkehr zu sparen.
  • Widerstandsfähigkeit gegen Verluste - garantierte Lieferung bei instabilen Netzwerkverbindungen.
  • Asynchron - Ermöglicht die Bedienung einer großen Anzahl von Geräten und ist nicht von Netzwerkverzögerungen abhängig.
  • QoS-Unterstützung - die Möglichkeit, die Nachrichtenpriorität zu steuern und die Nachrichtenübermittlung an den Empfänger zu gewährleisten.
  • Dynamische Konfiguration - erfordert keine vorherige Koordination von Feldern und Datenformaten, kann im laufenden Betrieb konfiguriert werden.
  • Funktioniert für NAT - Clients können sich hinter NAT befinden, nur der Server (Broker) muss eine echte IP haben. Ermöglicht den Verzicht auf VPN und Portweiterleitung.
  • Bequeme Adressierung - Datenfelder haben Textnamen, die für den Menschen verständlich sind. Sie müssen sich keine digitalen Adressen und Bit-Offsets merken.

In diesem Artikel werden wir MQTT und Modbus vergleichen, die Protokollstruktur und grundlegende Konzepte analysieren und versuchen, den Cloud-MQTT-Broker als Beispiel für eine instabile Internetverbindung zu verwenden.

MQTT-Protokollverlauf


MQTT wurde 1999 von IBM entwickelt und ursprünglich intern für seine Lösungen verwendet.

Im November 2011 gaben IBM und Eurotech ihre Teilnahme an der Eclipse M2M-Arbeitsgruppe und die Übertragung des MQTT-Codes an das Eclipse Paho-Projekt bekannt.

Im Jahr 2013 begann das Konsortium der OASIS (Organisation zur Förderung strukturierter Informationsstandards) mit der Standardisierung des MQTT-Protokolls. Bis zu diesem Zeitpunkt wurde die Protokollspezifikation unter einer kostenlosen Lizenz veröffentlicht, und Unternehmen wie Eurotech (früher bekannt als Arcom) verwenden das Protokoll bereits in ihren Produkten.

Im Oktober 2014 veröffentlichte OASIS den ersten offiziellen MQTT-Protokollstandard.

2016 wurde das Protokoll von der Internationalen Organisation für Normung ISO standardisiert und erhielt die Nummer ISO / IEC 20922.

Seit 2014 wächst das Interesse an dem Protokoll rapide und nach dem Google Trends-Zeitplan übersteigt es heute das Interesse an Modbus.


Google Trends Benchmark

Grundbegriffe


MQTT verfügt über eine Client-Server-Architektur. Das Messaging erfolgt über einen zentralen Server, der als Broker bezeichnet wird. Unter normalen Bedingungen können Clients nicht direkt miteinander kommunizieren, und der gesamte Datenaustausch erfolgt über einen Broker.

Clients können als Datenanbieter (Publisher) und als Datenempfänger (Subscriber) fungieren. In einer russischen Übersetzung werden diese Begriffe häufig als Herausgeber und Abonnent übersetzt. Um jedoch Verwirrung zu vermeiden, verwenden wir nur die ursprüngliche Terminologie.


Im MQTT-Protokoll kommunizieren Clients über einen zentralen Knoten miteinander

Auf Anwendungsebene läuft das Protokoll über TCP / IP und kann problemlos Remote-Objekte direkt über das Internet verbinden, ohne dass VPN-Tunnel erforderlich sind. Es reicht aus, wenn der Broker eine echte IP-Adresse hat und alle Clients eine Verbindung herstellen können. In diesem Fall befinden sich Clients möglicherweise hinter NAT. Da Clients die Verbindung im MQTT-Protokoll initiieren, ist keine Portweiterleitung erforderlich, um eine Verbindung herzustellen, während der Server in Modbus / TCP eine Verbindung (Master) initiiert, für die ein direkter Netzwerkzugriff erforderlich ist.

Der Standard-MQTT-Broker-Port für eingehende TCP-Verbindungen ist 1883 . Bei Verwendung einer sicheren SSL-Verbindung wird Port 8883 verwendet .

Makler


Ein Broker ist der zentrale MQTT-Hub für die Kundeninteraktion. Der Datenaustausch zwischen Kunden erfolgt nur über einen Broker. Der Broker kann eine Serversoftware oder ein Controller sein. Zu seinen Aufgaben gehören das Empfangen von Daten von Kunden, das Verarbeiten und Speichern von Daten, das Liefern von Daten an Kunden und das Überwachen der Nachrichtenübermittlung.

Herausgeber / Abonnent


Um den Unterschied zwischen Publisher und Subscriber zu verstehen, nehmen wir ein einfaches Beispiel: Ein Feuchtigkeitssensor misst die Luftfeuchtigkeit in einem Raum. Wenn sie unter einen bestimmten Wert fällt, schaltet sich der Luftbefeuchter ein.

In diesem Fall fungiert der Feuchtigkeitssensor als Herausgeber : Seine Aufgabe besteht nur darin, Daten im Broker zu veröffentlichen. Der Luftbefeuchter fungiert als Abonnent : Er abonniert Aktualisierungen der Feuchtigkeitsdaten und empfängt aktuelle Daten vom Broker, während der Luftbefeuchter entscheiden kann, wann die Luftbefeuchtung eingeschaltet werden soll.

In diesem Schema sind sich MQTT-Clients, dh der Sensor und der Luftbefeuchter, der Existenz des anderen nicht bewusst und interagieren nicht direkt. Der Broker kann Daten aus verschiedenen Quellen empfangen, bearbeiten, beispielsweise den Durchschnittswert von mehreren Sensoren berechnen und die verarbeiteten Daten an den Teilnehmer zurückgeben.


Der Publisher sendet Daten an den Broker, der Abonnent abonniert Aktualisierungen dieser Daten

Gleichzeitig bietet der Asynchronismus des MQTT-Protokolls, dass der Sensor und der Luftbefeuchter zu unterschiedlichen Zeiten online sein können, Pakete verlieren und nicht erreichbar sind. Der Broker sorgt dafür, dass die zuletzt vom Sensor empfangenen Daten im Speicher gespeichert werden und dass sie an den Luftbefeuchter geliefert werden.

Thema


MQTT verwendet Themen, um Entitäten zu identifizieren. In der russischen Übersetzung werden sie auch als Kanäle bezeichnet. Themen bestehen aus UTF8-Zeichen und haben eine Baumstruktur ähnlich einem UNIX-Dateisystem. Dies ist ein praktischer Mechanismus zum Benennen von Entitäten in einer für Menschen lesbaren Form.

Ein Beispiel für Themen in MQTT

#     home/kitchen/temperature #     home/sleeping-room/temperature #     home/outdoor/light 

Mit diesem Ansatz können Sie visuell sehen, welche Daten übertragen werden, und Sie können den Code bequem entwickeln und debuggen, ohne sich die digitale Adresse der Datenplatzierung merken zu müssen, wie dies bei Modbus der Fall ist.

Zu den Themen gehört auch die Platzhaltersyntax, die denjenigen vertraut ist, die mit dem UNIX-Dateisystem gearbeitet haben. Platzhalter können einstufig und mehrstufig sein.

Ein einstufiger Platzhalter ist mit einem + gekennzeichnet .

Um beispielsweise Daten von Temperatursensoren in allen Räumen des Hauses zu empfangen, muss der Teilnehmer ein solches Thema abonnieren:

 home/+/temperature 

Infolgedessen abonniert er den Empfang von Daten von solchen Sensoren:

 home/kitchen/temperature home/sleeping-room/temperature home/living-room/temperature home/outdoor/temperature 

Ein mehrstufiger Platzhalter wird durch das Symbol " # " angezeigt.
Ein Beispiel für das Abrufen von Daten von allen Sensoren in allen Räumen des Hauses:

 home/# 

Wenn Sie ein solches Thema abonnieren, können Sie Daten von solchen Sensoren empfangen:

 home/kitchen/temperature home/kitchen/humidity home/kitchen/light home/sleeping-room/temperature home/sleeping-room/humidity home/sleeping-room/light .... 

Kundenidentifikation


Für die Zugriffskontrolle bietet MQTT im Gegensatz zum Modbus-Protokoll, das keine solche Funktion hat, eine Clientauthentifizierung. Die folgenden Felder werden für die Zugriffskontrolle verwendet:

ClientId - (erforderliches Feld) eindeutige Kennung des Clients. Muss für jeden Kunden einzigartig sein. In der aktuellen Version des MQTT 3.1.1-Standards können Sie das leere Feld ClientId verwenden, wenn Sie den Verbindungsstatus nicht speichern müssen.

Benutzername - (optionales Feld) Anmeldung zur Authentifizierung im UTF-8-Format. Kann nicht einzigartig sein. Beispielsweise kann sich eine Gruppe von Clients mit demselben Benutzernamen / Kennwort anmelden.

Passwort - (optionales Feld) kann nur zusammen mit dem Feld Benutzername gesendet werden, während der Benutzername ohne das Feld Passwort übertragen werden kann. Maximal 65535 Bytes. Es ist wichtig zu wissen, dass der Name und das Passwort im Klartext übertragen werden. Wenn die Daten über öffentliche Netzwerke übertragen werden, müssen Sie die Verbindung mit SSL verschlüsseln.

Paketstruktur


Wie oben erwähnt, initiieren Clients im MQTT-Protokoll immer eine Verbindung, unabhängig davon, ob sie Empfänger (Abonnent) oder Lieferant (Herausgeber) von Daten sind. Wir werden das Paket mit der Verbindung analysieren, die mit dem Wireshark-Programm abgefangen wurde.


MQTT-Paket, das über einen unverschlüsselten Kanal übertragen wird

Der TCP-Header zeigt an, dass das Paket über Port 1883 gesendet wurde, dh, es wird keine Verschlüsselung verwendet. Dies bedeutet, dass alle Daten in klarer Form verfügbar sind, einschließlich Login und Passwort.

Überschrift


Der Nachrichtentyp ist Connect (Befehl 0x0001), wodurch eine Verbindung zum Broker hergestellt wird. Hauptteams: Verbinden, Trennen, Veröffentlichen, Abonnieren, Abbestellen. Es gibt auch Bestätigungsbefehle, am Leben bleiben usw.

Flag DUP - bedeutet, dass die Nachricht erneut übertragen wird. Sie wird nur in den Nachrichtentypen PUBLISH, SUBSCRIBE, UNSUBSCRIBE, PUBREL verwendet, wenn der Broker keine Bestätigung über den Empfang der vorherigen Nachricht erhalten hat.
QoS-Level - Flag der Servicequalität. Wir werden dieses Thema später genauer diskutieren.
Aufbewahrung - Mit dem Aufbewahrungsflag veröffentlichte Daten werden auf dem Broker gespeichert. Beim anschließenden Abonnement dieses Themas sendet der Broker sofort eine Nachricht mit diesem Flag. Wird nur in Nachrichten vom Typ Veröffentlichen verwendet.

Praktische Anwendung




Nachdem wir uns mit der Theorie vertraut gemacht haben, versuchen wir nun, in der Praxis mit MQTT zu arbeiten. Dazu verwenden wir das offene Mosquitto- Programm, das sowohl im Client-Modus als auch im Server-Modus (Broker-Modus) arbeiten kann. Es funktioniert unter Windows, MacOS, Linux. Das Programm ist sehr praktisch zum Debuggen und Studieren des MQTT-Protokolls, während es auch im industriellen Betrieb weit verbreitet ist. Wir werden es als Client verwenden, um Daten von einem Remote-Cloud-Broker zu senden und zu empfangen.

Viele Cloud-Anbieter bieten MQTT-Broker-Services an, z. B. Microsoft Azure IoT Hub , Amazon AWS IoT und andere. In diesem Beispiel verwenden wir den Cloudmqtt.com-Dienst, da er die einfachste Registrierung aufweist und ein kostenloser Tarif für Schulungen ausreicht.

Nach der Registrierung finden Sie in Ihrem Konto Details zur Verbindung mit einem Broker. Da wir über öffentliche Internetnetzwerke eine Verbindung zum Server herstellen, ist es sinnvoll, einen SSL-Port zum Verschlüsseln des Datenverkehrs zu verwenden.


Zugangsdaten zum MQTT-Broker im persönlichen Konto des Cloud-Anbieters

Die Flexibilität des MQTT-Protokolls ermöglicht es dem Client, Daten zu übertragen, die zuvor nicht auf dem Broker definiert wurden. Das heißt, es ist nicht erforderlich, die erforderlichen Themen vorab zu erstellen, in die Publisher Daten schreiben kann. Unter Verwendung der von Ihrem persönlichen Konto erhaltenen Daten werden wir versuchen, manuell eine Anforderung zum Veröffentlichen von Daten für das Thema habr / test / random zu erstellen und daraus zu lesen.

mosquitto_sub - Abonnenten-Client-Dienstprogramm
mosquitto_pub - Publisher-Client-Dienstprogramm

Stellen Sie zunächst als Abonnent eine Verbindung zum Broker her und abonnieren Sie, um Daten vom Thema zu erhalten
habr / test / random .

 mosquitto_sub -d --capath /etc/ssl/certs/ --url mqtts://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random Client mosq/zEPZz0glUiR4aEipZA sending CONNECT Client mosq/zEPZz0glUiR4aEipZA received CONNACK (0) Client mosq/zEPZz0glUiR4aEipZA sending SUBSCRIBE (Mid: 1, Topic: habr/test/random, QoS: 0, Options: 0x00) Client mosq/zEPZz0glUiR4aEipZA received SUBACK 

Es ist ersichtlich, dass die Verbindung erfolgreich war und wir das Thema habr / test / random abonniert haben. Jetzt warten wir auf Daten in diesem Thema vom Broker.
Da eine SSL-Verbindung verwendet wird, müssen Sie zur Überprüfung des Zertifikats den Pfad angeben, über den das Programm nach Stammverschlüsselungszertifikaten sucht. Da der Dienst in unserem Beispiel ein Zertifikat verwendet, das von einer vertrauenswürdigen Zertifizierungsstelle ausgestellt wurde, geben wir den Pfad zum Systemspeicher für Stammzertifikate an : --capath / etc / ssl / certs /

Bei einem selbstsignierten Zertifikat müssen Sie den Pfad zur gewünschten Zertifizierungsstelle angeben. Es ist auch wichtig, den Unterschied im URI-Format für SSL-Verbindungen - mqtt s : // und nicht verschlüsselte Verbindungen - mqtt: // zu berücksichtigen. Bei einem Zertifikatüberprüfungsfehler wird das Programm ohne Fehlermeldung beendet. Für eine detailliertere Ausgabe können Sie den Schalter --debug verwenden
Versuchen wir nun, die Daten im Thema zu veröffentlichen, ohne das erste Programm zu unterbrechen.

 mosquitto_pub -d --capath /etc/ssl/certs/ --url mqtt://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random -m " !" Client mosq/sWjh9gf8DRASrRZjk6 sending CONNECT Client mosq/sWjh9gf8DRASrRZjk6 received CONNACK (0) Client mosq/sWjh9gf8DRASrRZjk6 sending PUBLISH (d0, q0, r0, m1, 'habr/test/random', ... (22 bytes)) Client mosq/sWjh9gf8DRASrRZjk6 sending DISCONNECT 

Es ist ersichtlich, dass die Daten erfolgreich vom Server empfangen und im gewünschten Thema veröffentlicht wurden. Gleichzeitig sehen wir im ersten Fenster, in dem das Programm mosquitto_sub ausgeführt wird, wie die Nachricht empfangen wurde, auch wenn Unicode funktioniert, die Nachricht ist in russischer Sprache.

 Client mosq/zEPZz0glUiR4aEipZA received PUBLISH (d0, q0, r0, m0, 'habr/test/random', ... (22 bytes))  ! 

QoS und Liefergarantie


Das Senden einer Nachricht in Echtzeit wird jedoch niemanden überraschen, da dies auch mit dem banalen Dienstprogramm nc möglich ist . Daher werden wir versuchen, eine instabile Verbindung zwischen dem Teilnehmer und dem Absender zu simulieren. Stellen Sie sich vor, beide Clients arbeiten über GPRS mit einem enormen Paketverlust, und selbst eine erfolgreiche TCP-Verbindung ist selten. Sie müssen sicherstellen, dass der Teilnehmer garantiert eine Absendernachricht erhält. In diesem Fall helfen QoS-Optionen.

Standardmäßig ist das QoS- Flag für Nachrichten auf 0 gesetzt , was "Feuer und Vergessen" bedeutet: Publisher veröffentlicht die Nachricht auf dem Broker, erfordert jedoch nicht, dass die Nachricht garantiert an den Abonnenten zugestellt wird. Dies ist für Daten geeignet, deren Verlust nicht kritisch ist, beispielsweise für regelmäßige Messungen der Luftfeuchtigkeit oder Temperatur.

QoS 1: Mindestens einmal - mindestens einmal . Dieses Flag bedeutet, dass diese Veröffentlichung an den Broker und dann an den Abonnenten gesendet wird, bis der Publisher eine Zustellbestätigung an den Abonnenten erhält. Daher muss der Teilnehmer diese Nachricht mindestens einmal empfangen.

QoS 2: Genau einmal - garantiert eine . Das QoS-Flag, das die höchste Garantie für die Zustellung von Nachrichten bietet, indem zusätzliche Verfahren zur Bestätigung und zum Abschluss der Veröffentlichung verwendet werden (PUBREC, PUBREL, PUBCOMP). Anwendbar für Situationen, in denen der Verlust und die Vervielfältigung von Daten von Sensoren ausgeschlossen werden müssen. Wenn beispielsweise ein Alarm von einer empfangenen Nachricht ausgelöst wird, wird ein Notruf getätigt.

Um eine schlechte Kommunikation zu simulieren, deaktivieren Sie beide Clients und versuchen Sie, eine Nachricht mit der höchsten QoS-Priorität zu senden. Fügen Sie außerdem die Option Beibehalten hinzu, damit die gesendete Nachricht auf dem Broker gespeichert wird.

 mosquitto_pub --retain --qos 2 -d --capath /etc/ssl/certs/ --url mqtt://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random -m "  !" Client mosq/Xwhua3GAyyY9mMd05V sending CONNECT Client mosq/Xwhua3GAyyY9mMd05V received CONNACK (0) Client mosq/Xwhua3GAyyY9mMd05V sending PUBLISH (d0, q2, r1, m1, 'habr/test/random', ... (37 bytes)) Client mosq/Xwhua3GAyyY9mMd05V received PUBREC (Mid: 1) Client mosq/Xwhua3GAyyY9mMd05V sending PUBREL (m1) Client mosq/Xwhua3GAyyY9mMd05V received PUBCOMP (Mid: 1, RC:0) Client mosq/Xwhua3GAyyY9mMd05V sending DISCONNECT 

Nach einiger Zeit konnte unser Empfänger nun endlich eine Verbindung zum Internet herstellen und eine Verbindung zum Broker herstellen:

 mosquitto_sub -d --capath /etc/ssl/certs/ -d --url mqtts://hwjspxxt:7oYugN7Fa5Aa@postman.cloudmqtt.com:27529/habr/test/random Client mosq/VAzcLVMB1MiWhYxoJS sending CONNECT Client mosq/VAzcLVMB1MiWhYxoJS received CONNACK (0) Client mosq/VAzcLVMB1MiWhYxoJS sending SUBSCRIBE (Mid: 1, Topic: habr/test/random, QoS: 0, Options: 0x00) Client mosq/VAzcLVMB1MiWhYxoJS received SUBACK Subscribed (mid: 1): 0 Client mosq/r6UwPnDvx8aNInpPF6 received PUBLISH (d0, q0, r1, m0, 'habr/test/random', ... (37 bytes))   ! 

Fazit


MQTT ist ein modernes, fortschrittliches Protokoll, das viele der Nachteile seiner Vorgänger nicht aufweist. Dank seiner Flexibilität können Sie Clientgeräte hinzufügen, ohne einen Broker einzurichten, was erheblich Zeit spart. Die Eingabeschwelle zum Verständnis und zur Konfiguration des Protokolls ist recht niedrig, und das Vorhandensein von Bibliotheken für viele Programmiersprachen ermöglicht es Ihnen, einen beliebigen Technologie-Stack für die Entwicklung auszuwählen. Die Garantie für die Nachrichtenübermittlung unterscheidet MQTT erheblich von seinen Vorgängern und ermöglicht es Ihnen, keine Zeit damit zu verschwenden, Ihre eigenen Integritätskontrollmechanismen auf Netzwerkebene unnötig zu entwickeln.

Source: https://habr.com/ru/post/de452904/


All Articles