MQTT是基於TCP/IP協議棧構建的異步通信消息協議,是一種輕量級的發布/訂閱信息傳輸協議。MQTT在時間和空間上,將消息發送者與接受者分離,可以在不可靠的網絡環境中進行擴展。適用於設備硬件存儲空間有限或網絡帶寬有限的場景。物聯網平台支持設備使用MQTT協議接入。
官網:mqtt.org
wiki各種語言版本開發庫
https://github.com/mqtt/mqtt.github.io/wiki/libraries?spm=a2c4g.11186623.2.11.2d73174cN52z60
基礎概念
QoS
level 0:最多一次的傳輸
level 1:至少一次的傳輸
level 2:只有一次的傳輸
QoS0:對於client而言,有且僅發一次publish包,對於broker而言,有且僅發一次publish,簡而言之,就是僅發一次包,是否收到完全不管,適合那些不是很重要的數據。

QoS1:對於qos0而言,多了一次ack的作用,但是會有個問題,盡管我們可以通過確認來保證一定收到客戶端或服務器的message,但是我們卻不能保證message僅有一次,
也就是當client沒收到service的puback或者service沒有收到client的puback,那么就會一直發送publisher
流程:(publisher -> broker)
publisher store msg -> publish ->broker (傳遞message)
broker -> puback -> publisher delete msg (確認傳遞成功)
注意:
publisher必須保存msg,這樣才能在重發。
publisher如果在一定時間或socket斷開等異常情況,會繼續重發msg。

QoS2:對於qos1而言,qos2可以實現僅僅接受一次message,其主要原理,
publisher和broker進行了緩存,其中publisher緩存了message和msgID,而broker緩存了msgID,兩方都做記錄所以可以保證消息不重復,
但是由於記錄是需要刪除的,這個刪除流程同樣多了一倍。

流程:(publisher -> broker)
- publisher store msg -> publish ->broker -> broker store msgID(傳遞message)
- broker -> puberc (確認傳遞成功)
- publisher -> pubrel -> broker delete msgID (告訴broker刪除msgID)
- broker -> pubcomp -> publisher delete msg (告訴publisher刪除msg)
注意:第二步,即puberc不可以刪除 publisher的msg,因為第三步未必成功,這個時候就需要第一步提醒第二步繼續發,而提醒必須要msgID
Topic
物聯網平台中,服務端和設備端通過 Topic 來實現消息通信。Topic是針對設備的概念,Topic類是針對產品的概念。
產品的Topic類會自動映射到產品下的所有設備中,生成用於消息通信的具體設備Topic。 為了方便海量設備基於海量Topic進行通信,簡化授權操作,物聯網平台增加了產品Topic類的概念。
Topic類是一類Topic的集合。例如,產品的自定義Topic類/${YourProductKey}/${YourDeviceName}/user/update是具體Topic/${YourProductKey}/device1/user/update和
/${YourProductKey}/device2/user/update的集合。 在您創建設備后,產品的所有Topic類會自動映射到設備上。您無需單獨為每個設備授權Topic。
阿里物聯網平台,關於Topic類的說明:
- Topic類中,以正斜線(/)進行分層,區分每個類目。其中,有兩個類目為既定類目:${YourProductKey}表示產品的標識符ProductKey;${YourDeviceName}表示設備名稱。
- 類目命名只能包含字母,數字和下划線(_)。每級類目不能為空。
- 設備操作權限:發布表示設備可以往Topic發布消息;訂閱表示設備可以從Topic訂閱消息。
MQTT會話(Clean Session)
MQTT客戶端向服務器發起CONNECT請求時,可以通過’Clean Session’標志設置會話。
‘Clean Session’設置為0,表示創建一個持久會話,在客戶端斷開連接時,會話仍然保持並保存離線消息,直到會話超時注銷。
‘Clean Session’設置為1,表示創建一個新的臨時會話,在客戶端斷開時,會話自動銷毀。
不管clean session的值是什么,當終端設備離線時,QoS=0,1,2的消息一律接收不到。
當clean session的值為true,當終端設備離線再上線時,離線期間發來QoS=0,1,2的消息一律接收不到。
當clean session的值為false,當終端設備離線再上線時,離線期間發來QoS=0,1,2的消息仍然可以接收到。如果同個主題發了多條就接收多條,一條不差,照單全收。
MQTT保留消息(Retained Message)
MQTT客戶端向服務器發布(PUBLISH)消息時,可以設置保留消息(Retained Message)標志。保留消息(Retained Message)會駐留在消息服務器,后來的訂閱者訂閱主題時仍可以接收該消息。
Mnesia:retained_message
終端設備publish消息時,如果retain值是true,則服務器會一直記憶,哪怕是服務器重啟。因為Mnesia會本地持久化。
如果服務器接收到終端publish某主題的消息,payload為空且retain值是true,則會刪除這條持久化的消息。
如果服務器接收到終端publish某主題的消息,payload為空且retain值是false,則不會刪除這條持久化的消息。
Will Message
客戶端連接異常斷開時,由Broker將其遺囑消息發送給訂閱方。客戶端與Broker建立連接時將遺囑消息包含在CONNECT消息中發送給Broker。
Username/Password
建立連接時,CONNECT消息中可以攜帶用戶名和密碼用於身份校驗,但是默認是以明文方式傳輸,推薦使用TLS方式或者將密碼加密后再進行傳輸。
EMQ應用
emq官網:http://emqtt.io,基於Erlang/OTP開發,實現了MQTT V3.1和V3.1.1,支持MQTT-SN、COAP、WebSocket、STOMP和SockJS。提供量級、可依賴、公司級別的MQTT消息。
v2.0版本支持超過1.3million連接,需要配置內核、TCP stack、Erlang VM等,參考:http://emqtt.io/docs/v2/getstarted.html。服務器和client分離,常用於服務器。
EMQ支持windows和linux,使用方法相似,如下linux為例:
docker測試:
docker run -d --rm --name emqx -p 18083:18083-p 1883:1883 emqx/emqx
dashboard:
admin public
因為采用Erlang語言設計,提供的client庫也是erlang版本,沒有提供c版本,但兼容mosquitto庫,因此可用mosquitto_pub/mosquito_sub收發消息。
通過dashboard中的TOOLS/Websocket訂閱查查看消息(這是EMQ提供的測試工具,可用於測試mqtt收發),首先需要連接broker:
注:直接采用默認值連接即可。但要注意HOST主機IP必須是emqx主機IP,若采用docker,則為emqx docker IP,否則連接不成功。
參考:
-
什么是Topic
-
Mqtt精髓系列之連接建立過程
-
mqtt.github.io wiki各種語言版本開發庫
https://github.com/mqtt/mqtt.github.io/wiki/libraries?spm=a2c4g.11186623.2.11.2d73174cN52z60
11. 中移動MQTT庫,采用EPOLL框架監控輸入和MQTT cm-heclouds/MQTT
12. 中移動OneNet平台 http://open.iot.10086.cn/doc/multiprotocol/
13. 中移動OneNet SDK
14. EMQ集群及壓力測試總結 https://blog.csdn.net/xianglingchuan/article/details/82219344
