Následující článek navazuje na článek, který představoval protokol MQTT. V tomto článku byly představeny základní principy protokolu. Především tři typy uzlů – producent, konzument a jejich komunikačního zprostředkovatele.
Následujících pár řádek se věnuje malé rekapitulaci.
- v síti se nejdříve spustí zprostředkovatel – broker
- producent informace se zaregistruje ke zprostředkovateli na dané téma – topic
- konzument informace se rovněž zaregistruje ke zprostředkovateli na stejné téma – topic
V takto připravené síti je pak možné velmi snadno vyměňovat informace mezi producentem a konzumentem, přes jejich společné téma.
Implementací zprostředkovatele (brokeru) se zabývat nebudeme, ve většině případů si vystačíme s již hotovými řešeními. Celá řada z nich je open-source a tedy jejich zdrojové kódy jsou dostupné a jejich použití ve vlastních aplikacích je rovněž zdarma. Jedním z možných příkladů je mosquitto. Jedná se o lehkou implementaci MQTT brokera, který je (díky škálovatelnosti) možné využít jak na nevýkonných zařízeních, tak i na velmi výkoných serverech.
Pro pokračování v článku je nutné některého brokera nainstalovat. Pokud budete instalovat mosquitto, bude vše záležet na Vámi používané distribuci. Pro distribuce založené na Debianu lze použít následující příkaz.
# apt-get install mosquitto
Zbytek článku se bude zabývat již pouze klientskou částí, tedy producentu a konzumentu MQTT zpráv. Jako téměř ve všech případech, lze i k tomuto problému přistoupit ze dvou základních směrů. První možností je implementovat celý MQTT protokol. Dokumentace k tomuto protokolu je veřejně dostupná, například na http://mqtt.org/documentation.
Druhou a předvedenou možností je využití již existující knihovny, které tento protokol již implementuje. Výhoda tohoto přístupu je především v rychlosti, není nutné ztrácet čas vynalézáním kola. Jednou z možných knihoven je knihovna libmosquittopp. Jedná se vlastně o binding C++ rozhraní do standartní C knihovny libmosquitto, odvozené od projektu mosquitto.
Instalace této knihovny je opět vcelku snadná, záleží na použité distribuci. Instalační příkaz ale bude vždy vypadat velmi podobně následujícímu.
# apt-get install libmosquittopp-dev
Tolik tedy k přípravám prostředí a nyní již k vlastní implementaci MQTT klienta. Zdrojové kódy pro ukázkového klienta budou uloženy do jednoho .cpp souboru.
Několik poznámek ke zdrojovému kódu
- řádek 7 definice a implementace MQTT třídy, která je zděděna od mosquittopp
- řádek 19 definice konstruktoru, který vytvoří asynchronní spojení vůči MQTT brokeru
- řádek 22 inicializace mosquittopp knihovny, musí být vždy zavolána před použitím knihovny
- řádek 31 spuštění smyčky, která vybírá data z přijímacího socketu
- řádek 100 vytvoření instance MQTT klienta, připojení na localhost
- řádek 102 čekání na dokončení spojení
- řádek 107 přihlášení k tématu ‚/topic‘ na brokeru localhost
- řádek 113 nekonečná smyčka, vybírá přijaté pakety
Zdrojový kód je možné přeložit pomocí následujícího příkazu
$ g++ -std=c++11 mqtt-client.cpp -lmosquittopp -o mqtt_client
Nyní již následuje tolik zmiňovaný zdrojový kód.
#include <iostream> #include <mosquittopp.h> #include <string> using namespace std; class MQTT : public mosqpp::mosquittopp { private: bool connected; MQTT() = delete; // Constructor explicit MQTT(const char *id, bool clean) { } public: explicit MQTT(const string &host) { // call it first mosqpp::lib_init(); // send connect if(connect_async(host.c_str()) != MOSQ_ERR_SUCCESS) { cerr << "Async connect failed" << endl; } // start loop to read messages if(loop_start() != MOSQ_ERR_SUCCESS) { cerr << "Loop start failed" << endl; } } virtual ~MQTT() { } bool isConnected() const { return connected; } // inherited virtual methods virtual void on_connect(int rc) { if(rc != MOSQ_ERR_SUCCESS) { cerr << "Connect failed " << rc << endl; return; } cout << "Connected" << endl; connected = true; } virtual void on_disconnect(int rc) { cout << "Disconnected" << endl; connected = false; } virtual void on_publish(int mid) { cout << "Published with " << mid << endl; } virtual void on_message(const struct mosquitto_message *message) { cout << "Message received " << message->topic << endl; } virtual void on_subscribe(int mid, int qos_count, const int *granted_qos) { cout << "Subsribed" << endl; } virtual void on_unsubscribe(int mid) { cout << "Unsubscribed" << endl; } virtual void on_log(int level, const char *str) { cout << "[" << level << "] " << str << endl; } virtual void on_error() { cout << "Unknown error" << endl; } }; int main(int argc, char *argv[]) { cout << "MQTT start" << endl; MQTT mqtt("127.0.0.1"); while(! mqtt.isConnected()) { mqtt.loop(2000, 1); } if(mqtt.subscribe(nullptr, "/topic", 0) != 0) { cerr << "Subscribe send failed" << endl; mqtt.disconnect(); } while(true) { mqtt.loop(2000, 1); } }