Protokół MQTT #2: Paho Client

paho client

Jak wiadomo z poprzedniej części w modelu publish/subscribe występują dwa podstawowe elementy, pomiędzy którymi przesyłane są wiadomości. Są nimi klienci i broker. W naszym przypadku broker będzie zawsze gotowym rozwiązaniem, zainstalowanym gdzieś na komputerze albo udostępnionym w chmurze (np. Microsoft Azure, AWS), z którym będziemy się po prostu łączyli. Nie ma potrzeby i sensu stawiania go na niewielkim mikrokontrolerze. Z naszego punktu widzenia najbardziej interesujący jest klient i nim zajmiemy się w tym oraz następnych wpisach.

Wprowadzenie

W poprzedniej części wykorzystaliśmy gotowe programy klientów. Na początku, do przeprowadzania pierwszych testów, było to idealne rozwiązanie, ale do dalszej zabawy już nam to nie wystarcza. Chcemy przecież mieć zaimplementowanego klienta w naszej aplikacji, na naszej platformie: wysyłać i odbierać dane, a następnie je przetwarzać i podejmować odpowiednie działanie.

Implementacja klienta, mimo, że jest dużo prostsza niż brokera, nie jest banalną sprawą. Na nasze szczęście istnieje projekt Eclipse Paho, który zapewnia gotowe open-sourcowe biblioteki – implementacje klientów MQTT dostępne w wielu językach, na wiele platform. Do każdej biblioteki przygotowane są także demonstracyjne przykłady. Jest to kawał naprawdę świetnej roboty.

Jak wspomniałem biblioteki są dostępne w wielu językach: Java, C#, C++, Python i wiele innych. Są także gotowe biblioteki dla Arduino czy ESP8266. Z tego co zauważyłem to biblioteki we wszystkich językach wyglądają bardzo podobnie. Ja w tej części wykorzystam bibliotekę napisaną w języku C, a dokładnie MQTT C Client for Posix and Windows. Jak nazwa wskazuje biblioteka została napisana w standardzie POSIX – odnosi się to m.in. do obsługi stosu TCP/IP (np. POSIX Sockets) czy wielowątkowości (POSIX Threads). Najłatwiej będzie poznać tą bibliotekę w takiej formie, pracując pod systemem operacyjnym na PC albo np. Raspberry Pi, a dopiero potem próbować ją uruchomić na mniejszych mikrokontrolerach. W przyszłości tym też się zajmiemy, ale w razie czego więcej informacji dotyczących biblioteki dla embedded możesz znaleźć tutaj: Embedded MQTT C/C++ Client Libraries.

Budowanie biblioteki

Na podlinkowanej już wcześniej stronie znajdują się linki do kodów źródłowych oraz instrukcje instalacji zarówno dla systemu Linux jak i Windows. Ja będę korzystał z Linuxa i Tobie też to polecam – szczególnie jeśli wcześniej nie miałeś z nim zbyt dużo styczności. Jest okazja, żeby zacząć 🙂 Postaw maszynę wirtualną i do dzieła 😉

Zgodnie z instrukcją pobieramy pliki:

Zanim przejdziemy do budowania, konieczna jest jeszcze instalacja OpenSSL development package:

Przechodzimy do folderu, a następnie budujemy i instalujemy bibliotekę:

W folderze paho.mqtt.c/src znajdują się pliki źródłowe biblioteki klienta, a w folderze paho.mqtt.c/src/samples są gotowe przykłady wykorzystania biblioteki.

W folderze paho.mqtt.c/build/outputs znajdują się pliki skompilowanej biblioteki (*.so), a także wykonywalne pliki przykładów.

Sync vs Async

Klient może pracować w dwóch trybach: synchronicznym i asynchronicznym.

W trybie synchronicznym, wykonując jedno zadanie, trzeba poczekać do jego zakończenia zanim przejdzie się do wykonywania zadania kolejnego. Program działa w sposób blokujący, co jak można się domyślić, bardzo często wprowadza zbędne opóźnienia.  W przypadku trybu asynchronicznego można przejść do wykonywania kolejnych zadań bez konieczności czekania na zakończenie poprzedniego.

Klient pracujący w trybie synchronicznym działa na jednym wątku. Gdy wysyłamy jakąś wiadomość z QoS1 lub QoS2 i chcemy mieć pewność, że wiadomość została dostarczona z powodzeniem konieczne jest wywołanie blokującej funkcji MQTTClient_waitForCompletion(). W przypadku odbioru wiadomości, konieczne jest okresowe wywoływanie funkcji MQTTClient_receive(), która blokuje program do póki nie przyjdzie jakaś wiadomość lub nie upłynie timeout.

Klient pracujący w trybie asynchronicznym działa na wielu wątkach –  handshaking oraz podtrzymywanie połączenia jest realizowane w tle i nie trzeba się o to martwić. Kolejna istotna sprawa – wykorzystywany jest tutaj mechanizm funkcji zwrotnych (ang. callbacks), który już kiedyś opisywałem przy okazji wskaźników funkcyjnych. W takim wypadku wystarczy zdefiniować potrzebne funkcje, zarejestrować je, a następnie będą one automatycznie, asynchronicznie wywoływane, gdy wystąpi jakieś zdarzenie, np. gdy wysłana wiadomość zostanie dostarczona.

Rodzaje API

Biblioteka udostępnia dwa rodzaje API:

  • MQTT Client library for C: nastawiona jest na pracę klienta w trybie synchronicznym. Umożliwia, co prawda, także pracę w trybie asynchronicznym i ustawienie funkcji zwrotnych za pomocą funkcji MQTTClient_setCallbacks(), ale nie działa wtedy w sposób wątkowo-bezpieczny (ang. thread-safe). Jeśli chcemy korzystać z tego API należy dodać plik nagłówkowy MQTTClient.h oraz podlinkować bibliotekę o nazwie paho-mqtt3c.
  • Asynchronous MQTT client library for C: klient działa w sposób całkowicie asynchroniczny, nie ma funkcji blokujących i w odróżnieniu od poprzedniej jest wątkowo-bezpieczna. Funkcje zwrotne rejestruje się za pomocą MQTTAsync_setCallbacks(). Jeśli chcemy korzystać z tego API należy dodać plik nagłówkowy MQTTAsync.h oraz podlinkować bibliotekę o nazwie paho-mqtt3a.

Aby dodać skompilowane bilioteki w Eclipse lub jego pochodnych, wchodzimy w Project->Properties. W oknie, które się pojawiło rozwijamy C/C++ Build, gdzie wybieramy Settings. W GCC C Linker: libraries, w okienku Libraries (-l) dodajemy nazwę biblioteki:

Ścieżki nie musimy ustawiać, ponieważ przy instalacji biblioteki wszystkie potrzebne pliki zostały skopiowane do domyślnego folderu systemowego: /usr/local/lib.

Podsumowanie

W tym wpisie to już wszystko 🙂 Mamy wszystko przygotowane i znamy już podstawowe informacje na temat biblioteki. W kolejnej części dokładnie przerobimy przykład implementacji klienta publikującego, poznając przy tym część dostępnych struktur oraz funkcji bibliotecznych i przy okazji bardziej szczegółowo zgłębimy zasady i funkcjonalności występujące w protokole MQTT.

Do następnego, cześć 😉

Protokół MQTT #3: implementacja klienta