MQTT klient v C++

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

}

Posted

in

, ,

by

Tags: