Protokół MQTT #1: zasada działania

zasada działania MQTT

Tym wpisem rozpoczynamy serię na temat bardzo popularnego w IoT i M2M protokołu o nazwie MQTT. Jeśli interesujesz się koncepcją Internetu Rzeczy to pewnie już ta nazwa obiła Ci się kiedyś o uszy. Jeśli nie, to na pewno warto się z tym terminem zapoznać i teraz masz ku temu idealną okazję 🙂 Na początku przedstawię trochę teorii, a następnie wykorzystamy protokół w praktyce.

Wprowadzenie

MQTT jest otwartym protokołem komunikacyjnym, który wyróżnia lekkość i prostota, dzięki czemu można go z powodzeniem wykorzystywać na niewielkich mikrokontrolerach, przy ograniczonych zasobach sprzętowych, a także gdy mamy do czynienia z niską przepustowością łącza, co idealnie wpasowuje się w koncepcję IoT. Nie dziwi więc też fakt, że znajduje zastosowanie przy łączeniu urządzeń z chmurami (np. Amazon Web Services czy Microsoft Azure).  Wspierany jest przez wiele platform, takich jak Arduino, ESP8266 czy Raspberry Pi – istnieje wiele bibliotek i gotowych rozwiązań, dzięki czemu można łatwo, szybko i przyjemnie zacząć z niego korzystać.

MQTT, podobnie jak wszechobecny HTTP, znajduje się na samej górze stosu TCP/IP – w warstwie aplikacyjnej, jednak specyfika ich działania jest zupełnie inna. Jak widzisz, pojawiły się tutaj takie pojęcia jak HTTP i stos TCP/IP. Znajomość zagadnień sieciowych nie jest tutaj niezbędna – po przeczytaniu tej serii i bez tego będziesz w stanie korzystać z tego protokołu, ale podstawy zdecydowanie warto poznać. Szczególnie jeśli będziesz chciał wszystko zrozumieć i wykorzystywać go w trochę bardziej zaawansowanych przypadkach. Przydatny powinien być kurs na kanale youtube Pasja informatyki. Jeżeli zagadnienia sieciowe są Ci zupełnie obce to warto się z nimi zapoznać.

Jak to działa?

Protokół MQTT działa w oparciu o model publikacja/subskrypcja (ang. publish/subscribe), który umożliwia asynchroniczną komunikację pomiędzy klientami publikującymi (ang. publisher) i subskrybującymi (ang. subsciber).

Klientem MQTT nazywamy dowolne urządzenie podłączone do sieci (np. mikrokontroler, komputer) które ma zaimplementowany stos TCP/IP i protokół MQTT (potrafi komunikować się za jego pomocą). Istnieją gotowe biblioteki klientów MQTT w różnych językach, ale o tym dokładnie opowiem w kolejnej części. Warto jeszcze w tym miejscu wspomnieć, że jeden klient MQTT może jednocześnie pełnić funkcję subscribera i publishera.

Klienci, publisher i subscriber, nie komunikują się ze sobą bezpośrednio. Co więcej, jeden klient może przekazać wiadomość innemu klientowi bez znajomości jego adresu IP i wiedzy o jego istnieniu 🙂 Jak to jest możliwe? Otóż, pomiędzy klientami w modelu publish/subscribe zawsze występuje element pośredniczący – message broker. Odbiera on wiadomości od klientów publikujących, a następnie rozsyła je do odpowiednich klientów subskrybujących.

Tutaj pojawia się kolejne pytanie, skąd broker wie do których subskrybujących klientów przesłać daną wiadomość? Na nasze szczęście to też nie jest skomplikowane 🙂 Publisher, wysyłając wiadomość, dodaje do niej dodatkową informację – tekst nazywany tematem (ang. topic), a broker rozsyła wiadomość do tych klientów, którzy subskrybują ten temat. Bardzo dobrze przedstawia to poniższa grafika:

Dzięki takiemu mechanizmowi jeden klient może przekazać informację do wielu klientów i to bardzo małym kosztem: wystarczy, że wyśle wiadomość do brokera, a on już odwala za niego całą brudną robotę. I bardzo dobrze. Właśnie dzięki temu klienta możemy zaimplementować na małych mikrokontrolerach.

Oczywiście w takim wypadku broker potrzebuje już dużo większych zasobów. Może przecież być do niego podłączonych wielu klientów, musi filtrować i rozsyłać wiele wiadomości, zajmować się uwierzytelnianiem i autoryzacją klientów, a także przechowywaniem wiadomości. W związku z tym instaluje się go na wydajniejszych platformach. Na szczęście, podobnie jak w przypadku klienta, istnieją gotowe rozwiązania do wykorzystania – zarówno płatne jak i darmowe.

MQTT w praktyce

Wiemy już z grubsza jak protokół działa w teorii, czas przejść do praktyki. Zajmiemy się teraz instalacją brokera i klientów, żeby w praktyce sprawdzić ich działanie. Zaczniemy od instalacji brokera. Istnieją jego różne implementacje, bardzo popularny jest np. open-sourcowy broker Eclipse Mosquitto i właśnie go tutaj wykorzystamy. Na stronie producenta znajdziesz potrzebne pliki dla różnych systemów operacyjnych oraz instrukcję instalacji. Jeśli korzystasz z Linuxa na PC albo Raspberry Pi to sprawa jest banalnie prosta – wystarczy w konsoli wpisać:

Po instalacji brokera trzeba jeszcze zainstalować programy klientów:

Aby uruchomić broker wystarczy w konstoli wpisać mosquitto. Jak widać broker domyślnie słucha na porcie 1883:

Teraz przejdziemy do uruchomienia klientów. Zacznijmy od subskrybenta – program nazywa się mosquitto_sub. Uruchamiamy go w nowej konsoli lub z innego urządzenia:

Znaczenie poszczególnych flag:

  • -t  : nazwa subskrybowanego tematu
  • -h : adres IP brokera. W tym przypadku broker i klient uruchomione są na tej samej maszynie – podajemy adres localhosta (w takim wypadku, nie ma konieczności ustawiania tej flagi, ponieważ jest to wartość domyślna)
  • -p : numer portu (w tym przypadku także można było pominąć tą flagę, ponieważ 1883 jest wartością domyślną)

Opis wszystkich dostępnych flag można sprawdzić poprzez wpisanie w konsoli:

Po uruchomieniu, program czeka na wiadomości i jeśli jakąś otrzyma to wyświetli nam ją w konsoli. Natomiast broker pokazuje, że nastąpiło połączenie:

Czas przesłać jakąś wiadomość. Do tego celu służy program mosquitto_pub, który możemy uruchomić poprzez wpisanie w nowej konsoli:

Jak widać doszła nowa flaga:

  • -m : treść przesyłanej wiadomości.

Ja w tym przypadku zdecydowałem się wysłać coś z innego komputera, działającego pod windowsem. Wygląda to identycznie: klienta także uruchamiamy z poziomu konsoli. Jedyne o czym należy pamiętać to przejście do katalogu, gdzie został zainstalowany mosquitto oraz podanie adresu IP hosta, na którym postawiony jest broker, a nie localhosta.

I w ten oto sposób do naszego subskrybującego klienta doszła wiadomość:

Jak widać sprawa wygląda bardzo prosto. Polecam jeszcze pokombinować z różnymi hostami, portami, nazwami tematów i zobaczyć co się dzieje 🙂

Tematy wiadomości

Dotychczas używaliśmy najprostszych nazw tematów. Warto trochę dokładniej omówić to zagadnienie. Po pierwsze wielkość liter ma znaczenie i nazwy tematów „Test” oraz „test” będą traktowane jako dwa różne. Kolejną, bardzo istotną rzeczą jest to, że istnieje możliwość tworzenia tematów wielopoziomowych i warto z tej możliwości korzystać 🙂 W takiej sytuacji każdy poziom oddzielamy znakiem „/”, np.:

Dzięki wprowadzonej wielopoziomowości klient ma możliwość subskrypcji grupy tematów i służą do tego znaki specjalne. Klient może subskrybować temat „warehouse/01/temperature” i otrzymywać temperaturę z magazynu pierwszego, ale może też poprosić brokera o temperatury ze wszystkich magazynów. W takiej sytuacji wykorzystywany jest znak „+”:

Co istotne, znak „+” obejmuje tylko jeden poziom. To znaczy, że subskrybent otrzyma wiadomości z tematami:

ale z tematami:

już nie.

Istnieje także możliwość subskrypcji tematów z wielu poziomów, ale w takim wypadku należy wykorzystać znak „#”. Dla przykładu, klient subskrybujący temat „warehouse/01/#” będzie otrzymywał wiadomości o tematach:

A w przypadku subskrypcji „warehouse/#” będzie otrzymywał wartości wszystkich parametrów ze wszystkich magazynów. Inaczej mówiąc, dostanie wszystkie wiadomości o tematach rozpoczynających się od „warehouse/„.

QoS – Quality of Service

Przy transmisji danych w sieciach komputerowych dosyć często spotykanym pojęciem jest tzw. QoS – Quality of Service. Jest ono także wykorzystywane w przypadku protokołu MQTT, który zapewnia trzy poziomy QoS w odniesieniu do gwarancji dostarczania wiadomości pomiędzy serwerem i klientami.

  •  QoS0 (at most once): wiadomość może zostać dostarczona co najwyżej raz lub nie zostać dostarczona w ogóle. Przy tak ustawionej wartości QoS wiadomości nie są przechowywane przez nadawcę (broker lub publisher) i nie są wykorzystywane potwierdzenia odbioru oraz realizowane ewentualne retransmisje.
  •  QoS1 (at least once): wiadomość zostanie dostarczona co najmniej raz, ale może także dojść do zduplikowania wiadomości. Przy tak ustawionej wartości QoS wykorzystywane są potwierdzenia odbioru i nadawca przechowuje wiadomości na wypadek konieczności retransmisji.
  •  QoS2 (exactly once): wybór tej wartości QoS zapewnia najwyższą jakość i gwarantuje dostarczenie wiadomości dokładnie raz. Wymaga jednak najbardziej złożonego systemu potwierdzeń przez co transmisja trwa najdłużej.

Warto jeszcze tutaj zwrócić uwagę na jedną rzecz: publisher przesyłając wiadomość do brokera ustawia jej określoną wartość QoS. Subscriber odbierający wiadomość od brokera także może to robić z dowolną wartością QoS. W związku z tym, poziom QoS jednej wiadomości przekazywanej na drodze publisher – broker i broker – subscriber może mieć różne wartości. Dlatego wiadomość wysłana przez publishera z QoS1 lub QoS2 mimo wszystko może nie dojść do subscribera, jeśli ten będzie subskrybwał dany temat z QoS0.

Podsumowanie

No i podstawową teorię oraz najważniejsze informacje dotyczące protokołu MQTT mamy za sobą 😉 Jak wspominałem na początku, MQTT jest świetnym protokołem dla aplikacji IoT, więc jeśli interesuje Cię ta tematyka to zdecydowanie warto poznać go trochę dokładniej – do przepracowania jest jeszcze kilka zagadnień 🙂

Na razie do obsługi klientów wykorzystaliśmy gotowe programy z poziomu konsoli. W następnym wpisie zajmiemy się tematem implementacji klienta, aby móc napisać własny program umożliwiający wysyłanie lub subskrybowanie wiadomości. Do zobaczenia w kolejnej części 🙂

Protokół MQTT #2: Paho Client