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);
}
}
