物聯網網路協議-MQTT協議的使用
非加密訊息傳輸
物聯網系統中網路協議是物聯網設備之間溝通的“語言”,使用同一種語言,雙方才能通信成功,MQTT 協議是最流行的一種,它甚至已經成為物聯網系統事實上的網路協議標準,
第一步是安裝 hbmqtt,它是一個開源的基于 Python 語言的 MQTT Broker 軟體,正好包括我們需要使用一些工具,hbmqtt通過打開終端輸入 pip 命令就可以安裝,這也是選擇使用它的主要原因,
不過要注意的是,hbmqtt 是基于 Python3 實作的,因此這里使用的是 pip3 工具,
pip3 install hbmqtt
安裝完成后,我們就可以使用 hbmqtt 中提供的 hbmqtt_sub 和 hbmqtt_pub 這兩個命令列工具了,通過名字,你應該也可以看出 hbmqtt_sub 可以充當訂閱者的角色;hbmqtt_pub 可以作為訊息的發布者,
至于訂閱者和發布者之間的經紀人,也就是 MQTT Broker,我們使用 Eclipse 免費開放的在線 Broker 服務,
鏈接: link.
打開鏈接,你可以看到關于埠的介紹資訊,加密和非加密方式都支持,而且還有基于 Websocket 的實作,這對基于前端網頁的應用來說是非常有利的,
我們先使用 1883 埠的非加密方式,然后為訊息傳輸確定一個主題(Topic),主題確定了訊息的類別,用于訊息過濾,我們可以把主題可以設為“/geektime/iot”,
/geektime/iot
接著,我們在電腦的終端界面輸入下面的命令,就可以訂閱這個主題訊息:
hbmqtt_sub --url mqtt://mqtt.eclipse.org:1883 -t /geektime/iot
如果你想了解一些命令的執行細節,可以在上面的命令中加上 “-d” 引數,
現在,我們啟動另外一個終端界面,通過 hbmqtt_pub 發布一個 “/geektime/iot” 主題的訊息:
hbmqtt_pub --url mqtt://mqtt.eclipse.org:1883 -t /geektime/iot -m Hello,World!
通過 Eclipse 的開放 Broker 作為“經紀人”,訊息被傳輸到了我們通過 hbmqtt_sub 運行的訂閱者那里,下圖是終端界面上運行的結果,一個完整的訊息傳輸程序就這樣完成了,

MQTT 在物聯網領域的優勢
MQTT 的生態很完善
在使用 MQTT 的時候會覺得很方便,可供挑選的方案有很多,可以支持多種語言,類似的 MQTT Broker 軟體,你還可以選擇基于 C 語言的Mosquitto,基于 Erlang 語言的VerneMQ等,
至于 MQTT 的客戶端(Client)實作,也有成熟的 Python、C、Java 和 JavaScript 等各種編程語言的開源實作,
而且,還有很多商業公司在持續運營功能更豐富、支持更完備的商業版 Broker 實作,比如提供高并發能力的集群特性、方便拓展的插件機制等,這些會大大提高我們技術開發者的作業效率,
MQTT 自身的“基因”很強大
阿里云、華為云、騰訊云和微軟 Azure 這些大廠,之所以不約而同地選擇 MQTT 協議作為物聯網設備的“第一語言”,不僅是因為 MQTT 的生態完善,MQTT 協議本身的優秀設計也是重要的因素,
它在設計上的優點體現在主要有五個方面:
1.契合物聯網大部分應用場景的發布 - 訂閱模式,
2.能夠滿足物聯網中資源受限設備需要的輕量級特性,
3.時刻關注物聯網設備低功耗需求的優化設計,
4.針對物聯網中多變的網路環境提供的多種服務質量等級,
5.支持在物聯網應用中越來越被重視的資料安全,
發布 - 訂閱模式
剛才通信程序,是一個發布者和一個訂閱者的情況,在這之后,你可以再打開一個終端界面,重復和之前一樣的命令,再啟動一個訂閱者,
hbmqtt_sub --url mqtt://mqtt.eclipse.org:1883 -t /geektime/iot
現在,這兩個訂閱者都訂閱了“/geektime/iot” 主題的訊息,
然后,你再次使用 hbmqtt_pub 發送訊息,就可以看到兩個訂閱者都收到了同樣的訊息,這是發布 - 訂閱模式的典型特征,
因為采用了發布 - 訂閱模式,MQTT 協議具有很多優點,
比如能讓一個傳感器資料觸發一系列動作;
網路不穩定造成的臨時離線不會影響作業;
方便根據需求動態調整系統規模等,
這使得它能滿足絕大部分物聯網場景的需求,
輕量級協議:減少傳輸資料量
MQTT 是一個輕量級的網路協議,這一點也是它在物聯網系統中流行的重要原因,畢竟物聯網中大量的都是計算資源有限、網路帶寬低的設備,
這種“輕量級”體現在兩個方面,
一方面,MQTT 訊息采用二進制的編碼格式,而不是 HTTP 協議那樣的文本的表述方式,
這樣子做的好處就是可以充分利用位元組位,協議頭可以很緊湊,從而盡量減少需要通過網路傳輸的資料量,
比如,分析 HTTP 的一個請求抓包,它的訊息內容是下面這樣的(注意:空格和回車、換行符都是訊息的組成部分):
GET /account HTTP/1.1 <--注釋:HTTP請求行
Host: time.geekbang.com <--注釋:以下為HTTP請求頭部
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:81.0) Gecko/20100101 Firefox/81.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
<--注釋:這個空行是必須的,即使下面的請求體是空的
在 HTTP 協議傳輸的這段文本中,每個字符都要占用 1 個位元組,而如果使用 MQTT 協議,一個位元組就可以表示很多內容,下面的圖片展示了 MQTT 的固定頭的格式,這個固定頭只有 2 個位元組:

第一個位元組分成了高 4 位(4~7)和低 4 位(0~3);低 4 位是資料包標識位,其中的每一位元位又可以表示不同的含義;高 4 位是不同資料包型別的標識位,
第二個位元組表示資料包頭部和訊息體的位元組共個數,其中最高位表示有沒有第三位元組存在,來和第二個位元組一起表示位元組共個數,
如果有第三個位元組,那它的最高位表示是否有第四個位元組,來和第二個位元組、第三個位元組一起表示位元組總個數,依此類推,還可能有第四個位元組、第五個位元組,不過這個表示可變頭部和訊息體的位元組個數的部分,最多也只能到第五個位元組,所以可以表示的最大資料包長度有 256MB,
比如,一個請求建立連接的 CONNECT 型別資料包,頭部需要 14 個位元組;發布訊息的 PUBLISH 型別資料包頭部只有 2~4 個位元組,
輕量級的另一方面,體現在訊息的具體互動流程設計非常簡單,所以 MQTT 的互動訊息型別也非常少,為了方便后面的講解,我在這里整理了一個表格,總結了 MQTT 不同的資料包型別的功能和發訊息的流向,
從表格可以看出,MQTT 3.1.1 版本一共定義了 14 種資料包的型別,在第一個位元組的高 4 位中分別對應從 1 到 14 的數值,

功耗優化:節約電量和網路資源
除了讓協議足夠輕量,MQTT 協議還很注重低功耗的優化設計,這主要體現在對能耗和通信次數的優化,
比如,MQTT 協議有一個 Keepalive 機制,它的作用是,在 Client 和 Broker 的連接中斷時,讓雙方能及時發現,并重新建立 MQTT 連接,保證主題訊息的可靠傳輸,
這個機制作業的原理是:Client 和 Broker 都基于 Keepalive 確定的時間長度,來判斷一段時間內是否有訊息在雙方之間傳輸,這個 Keepalive 時間長度是在 Client 建立連接時設定的,如果超出這個時間長度,雙方沒有收到新的資料包,那么就判定連接斷開,
除了 Keepalive 機制,MQTT 5.0 中的重復主題特性也能幫助我們節省網路資源,
Client 在重復發送一個主題的訊息時,可以從第二次開始,將主題名長度設定為 0,這樣 Broker 會自動按照上次的主題來處理訊息,這種情況對傳感器設備來說十分常見,所以這個特性在作業中很有實際意義,
3 種 QoS 級別:可靠通信
除了計算資源有限、網路帶寬低,物聯網設備還經常遇到網路環境不穩定的問題,尤其是在移動通信、衛星通信這樣的場景下,比如共享單車,如果用戶已經鎖車的這個訊息,不能可靠地上傳到服務器,那么計費就會出現錯誤,結果引起用戶的抱怨,這樣怎么應對呢?
這個問題產生的背景就是不穩定的通信條件,所以 MQTT 協議設計了 3 種不同的 QoS (Quality of Service,服務質量)級別,你可以根據場景靈活選擇,在不同環境下保證通信是可靠的,
這 3 種級別分別是:
QoS 0,表示訊息最多收到一次,即訊息可能丟失,但是不會重復,
QoS 1,表示訊息至少收到一次,即訊息保證送達,但是可能重復,
QoS 2,表示訊息只會收到一次,即訊息有且只有一次,

我用一張圖展示了它們各自的特點,可以看到,QoS 0 和 QoS 1 的流程相對比較簡單;而 QoS 2 為了保證有且只有一次的可靠傳輸,流程相對復雜些,
正常情況下,QoS 2 有 PUBLISH、PUBREC、PUBREL 和 PUBCOMP 4 次互動,
至于“不正常的情況”,發送方就需要重復發送訊息,比如一段時間內沒有收到 PUBREC 訊息,就需要再次發送 PUBLISH 訊息,不過要注意,這時要把訊息中的 “重復”標識設定為 1,以便接收方能正確處理,同樣地,如果沒有收到 PUBCOMP 訊息,發送方就需要再次發送 PUBREL 訊息,
安全傳輸
說到安全傳輸,首先我們需要驗證 Client 是否有權限接入 MQTT Broker,為了控制 Client 的接入,MQTT 提供了用戶名 / 密碼的機制,在建立連接程序中,它可以通過判斷用戶名和密碼的正確性,來篩選有效連接請求,但是光靠這個機制,還不能保證網路通信程序中的資料安全,因為在明文傳輸的方式下,不止設備資料,甚至用戶名和密碼都可能被其他人從網路上截獲而導致泄漏,于是其他人就可以偽裝成合法的設備發送資料,
所以還需要通信加密技術的支持,
MQTT 協議支持 SSL/TLS 加密通信方式,采用 SSL/TLS 加密之后,MQTT 將轉換為 MQTTS,這有點類似于 HTTP 和 HTTPS 的關系,
我們只要將前面測驗的命令修改一下,將 “mqtt://” 改為 “mqtts://”,埠改為 8883,就可以用 SSL/TLS 加密通信方式連接到 Eclipse 提供的開放 Broker,
如果這個的 SSL 證書已經過期了,連接會失敗,
這里再提供另一個方式,供測驗使用)
輸入“mqtts://test.mosquitto.org:8883”,把開放 Broker 切換到這個鏈接,
鏈接: link.
從鏈接中下載一個客戶端證書,然后通過下面的命令訂閱主題訊息:
hbmqtt_sub --url mqtts://test.mosquitto.org:8883 -t /geektime/iot --ca-file ~/Downloads/mosquitto.org.crt
接著,我們再通過下面的命令測驗發布訊息:
hbmqtt_pub --url mqtts://test.mosquitto.org:8883 -t /geektime/iot -m Hello,World! --ca-file ~/Downloads/mosquitto.org.crt
最后在運行 hbmqtt_sub 命令的終端,就可以看到 Hello,World! 的訊息:

學習筆記總結自‘物聯網開發實戰’–郭朝斌
–筆記只用于學習交流,請不要用于商業用途,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/260132.html
標籤:其他
上一篇:基于51單片機制作的藍牙小車
下一篇:云計算專業防火墻混合模式應用實驗
