MQTT協議簡記

 1、定義

MQTT - MQ Telemetry Transport

  • 輕量級的 machine-to-machine 通訊協議。
  • publish/subscribe模式。
  • 基於TCP/IP。
  • 支持QoS。
  • 適合於低帶寬、不可靠鏈接、嵌入式設備、CPU內存資源緊張。
  • 是一種比較不錯的Android消息推送方案。
  • FacebookMessenger採用了MQTT。
  • MQTT有可能成爲物聯網的重要協議。
 

MQTT是輕量級基於代理的發佈/訂閱的消息傳輸協議,它能夠經過不多的代碼和帶寬和遠程設備鏈接。例如經過衛星和代理鏈接,經過撥號和醫療保健提供者鏈接,以及在一些自動化或小型設備上,並且因爲小巧,省電,協議開銷小和能高效的向一和多個接收者傳遞信息,故一樣適用於稱動應用設備上。php

相信在想深刻學習這協議必是奔着解決某個問題而來的,上面給出了適用的場景,我之因此想深刻的學習和了解這個協議,理由以下:linux

一、能夠實現手機消息推送(PUSH)服務器

二、協議簡單,最小的頭部只需2個字節,特別適合於嵌入式中。session

三、這是個瞭解什麼是協議絕好的例子。相比於其它複雜的協議例如tcp,http協議,至少說明文檔看的下去。socket

在這裏,我以推送爲例子說明,雖然如今現成的推送解決方案已經比較成熟,可是這個Repeat ReInvent the Whell仍是要作一下,什麼都是拿來主義,和搬運工有什麼區別。tcp

 

2、協議初解

先說一下整個協議的構造,總體上協議可拆分爲:ide

  固定頭部+可變頭部+消息體學習

協議說白了就是對於雙方通訊的一個約定,好比傳過來一段字符流,第1個字節表示什麼,第2個字節表示什麼。。。。一個約定。ui

因此在固定頭部的構造以下:編碼

 

一、MessageType

 
 
MessageType(0和15保留,共佔4個字節)
public $operations=array(
         "MQTT_CONNECT"=>1,//請求鏈接
         "MQTT_CONNACK"=>2,//請求應答
         "MQTT_PUBLISH"=>3,//發佈消息
         "MQTT_PUBACK"=>4,//發佈應答
         "MQTT_PUBREC"=>5,//發佈已接收,保證傳遞1
         "MQTT_PUBREL"=>6,//發佈釋放,保證傳遞2
         "MQTT_PUBCOMP"=>7,//發佈完成,保證傳遞3
         "MQTT_SUBSCRIBE"=>8,//訂閱請求
         "MQTT_SUBACK"=>9,//訂閱應答
         "MQTT_UNSUBSCRIBE"=>10,//取消訂閱
         "MQTT_UNSUBACK"=>11,//取消訂閱應答
         "MQTT_PINGREQ"=>12,//ping請求
         "MQTT_PINGRESP"=>13,//ping響應
         "MQTT_DISCONNECT"=>14//斷開鏈接
        ); 
CONNECT
TCP鏈接創建完畢後,Client向Server發出一個Request。
若是一段時間內接收不到Server的Response,則關閉socket,從新創建一個session鏈接。
若是一個ClientID已經與服務器鏈接,則持有一樣ClientID的舊有鏈接必須由服務器關閉後,新創建才能創建。
 
CONNACK
Server發出Response響應。
0x00 Connection Accepted
0x01 Connection Refused: unacceptable protocol version
0x02 Connection Refused: identifier rejected
0x03 Connection Refused: server unavailable
0x04 Connection Refused: bad user name or password
0x05 Connection Refused: not authorized
 
PUBLISH 發佈消息
Client/Servier都可以進行PUBLISH。
publish message 應該包含一個TopicName(Subject/Channel),即訂閱關鍵詞。
 
關於Topic通配符
/:用來表示層次,好比a/b,a/b/c。
#:表示匹配>=0個層次,好比a/#就匹配a/,a/b,a/b/c。
單獨的一個#表示匹配全部。
不容許 a#和a/#/c。
+:表示匹配一個層次,例如a/+匹配a/b,a/c,不匹配a/b/c。
單獨的一個+是容許的,a+不容許,a/+/b不容許
 
PUBACK 發佈消息後的確認
QoS=1時,Server向Client發佈該確認(Client收到確認後刪除),訂閱者向Server發佈確認。
 
PUBREC / PUBREL / PUBCOMP
QoS=2時
1. Server->Client發佈PUBREC(已收到);
2. Client->Server發佈PUBREL(已釋放);
3. Server->Client發佈PUBCOMP(已完成),Client刪除msg;
訂閱者也會向Server發佈相似過程確認。
 
PINGREQ / PINGRES 心跳
Client有責任發送KeepAliveTime時長告訴給Server。在一個時長內,發送PINGREQ,Server發送PINGRES確認。
Server在1.5個時長內未收到PINGREQ,就斷開鏈接。
Client在1個時長內未收到PINGRES,斷開鏈接。
通常來講,時長設置爲幾個分鐘。最大18hours,0表示一直未斷開。
 
 

二、DUP flag

 其是用來在保證消息傳輸可靠的,若是設置爲1,則在下面的變長頭部裏多加MessageId,並須要回覆確認,保證消息傳輸完成,但不能用於檢測消息重複發送。

三、QoS

 主要用於PUBLISH(發佈態)消息的,保證消息傳遞的次數。
 11保留後用
 
QoS=0:最多一次,有可能重複或丟失。
 
QoS=1:至少一次,有可能重複。
Client[Qos=1,DUP=0/*重複次數*/,MessageId=x] --->PUBLISH--> Server收到後,存儲Message,發佈,刪除,向Client回發PUBACK
Client收到PUBACK後,刪除Message;若是未收到PUBACK,設置DUP++,從新發送,Server端從新發布,因此有可能重複發送消息。
 
QoS=2:只有一次,確保消息只到達一次(用於比較嚴格的計費系統)。
 
 

四、Retain

 主要用於PUBLISH(發佈態)的消息,表示服務器要保留此次推送的信息,若是有新的訂閱者出現,就把這消息推送給它。若是不設那麼推送至當前訂閱的就釋放了。

 

五、固定頭部的byte 2

是用來保存接下去的變長頭部+消息體的總大小的。

可是不是並非直接保存的,一樣也是能夠擴展的,其機制是,前7位用於保存長度,後一部用作標識。

我舉個例了,即若是計算出後面的大小爲0<length<=127的,正常保存

若是是127<length<16383的,則須要二個字節保存了,將第一個字節的最大的一位置1,表示未完。而後第二個字節繼續存。

拿130來講,第一個字節存10000011,第二個字節存000000001,也就是0x83,0x01,把兩個字節連起來看,第二個字節權重從2的8次開始。

同起能夠加第3個字節,最多能夠加至第4個字節。故MQTT協議最多能夠實現268 435 455 (0xFF, 0xFF, 0xFF, 0x7F)將近256M的數據。可謂能伸能縮。

 可變頭部

這個是可變頭部的全貌。

一、首先最上面的8個字節是Protocol Name(編碼名),UTF編碼的字符「MQIsdp」,頭兩個是編碼名提長爲6。

這裏多說一些,接下去的協議多采用這種方式組合,即頭兩個字節表示下一部分的長,而後後面跟上內容。這裏頭兩個字節長爲6,下面跟6個字符「MQIsdp」。

二、Protocol Version,協議版本號,v3 也是固定的。

三、Connect Flag,鏈接標識,有點像固定頭部的。8位分別表明不一樣的標誌。第1個字節保留。

Clean Session,Will flag,Will Qos, Will Retain都是相對於CONNECT消息來講的。

Clean Session:0表示若是訂閱的客戶機斷線了,那麼要保存其要推送的消息,若是其從新鏈接時,則將這些消息推送。

                            1表示消除,表示客戶機是第一次鏈接,消息因此之前的鏈接信息。

Will Flag,表示若是客戶機在不是在發送DISCONNECT消息中斷,好比IO錯誤等,將些置爲1,要求重傳。而且下且的WillQos和WillRetain也要設置,消息體中的Topic和MessageID也要設置,就是表示發生了錯誤,要重傳。

Will Qos,在CONNECT非正常狀況下設置,通常若是標識了WillFlag,那麼這個位置也要標識。

Will RETAIN:一樣在CONNECT中,若是標識了WillFlag,那麼些位也必定要標識

usename flag和passwordflag,用來標識是否在消息體中傳遞用戶和密碼,只有標識了,消息體中的用戶名和密碼才用效,只標記密碼而不標記用戶名是不合法的。

四、Keep Alive,表示響應時間,若是這個時間內,鏈接或發送操做未完成,則斷開tcp鏈接,表示離線。

五、Connect Return Code即一般於CONNACK消息中,表示返回的鏈接狀況,我能夠經過此檢驗鏈接狀況。

六、Topic Name,訂閱消息標識,MQTT是基於訂閱/發佈的消息,那麼這個就是消息訂閱的標識,像新聞客戶端裏的訂閱不一樣的欄目同樣。用於區別消息的推送類別。

主要用於PUBLISH和SUBSCRIBE中。最大可支持32767個字符,即4個字節。

消息體(PayLoad)

只有3種消息有消息體CONNECT,SUBSCRIBE,SUBACK

CONNECT主要是客戶機的ClientID,訂閱的Topic和Message以及用戶名和密碼,其於變長頭部中的will是對應的。

SUBSCRIBE是包含了一系列的要訂閱的主題以及QOS。

SUBACK是用服務器對於SUBSCRIBE所申請的主題及QOS進行確認和回覆。

PUBLISH是消息體中則保存推送的消息,以二進制形式,固然這裏的編輯可自定義。

七、Message Identifier

包含於PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK.

其爲16位字符表示,用於在Qos爲1或2時標識Message的,保證Message傳輸的可靠性。

至於具體的消息例子,咱們在後面的代碼中慢慢體現。

 

Clean Session

 
若是爲false(flag=0),Client斷開鏈接後,Server應該保存Client的訂閱信息。
若是爲true(flag=1),表示Server應該馬上丟棄任何會話狀態信息。
 

3、須要的環境:

一、PHP+Apache或Nginx

二、安裝開源代理程序Mosquitto,這裏用其作爲代理服務器,負責鏈接和分發。

安裝方法很簡單,http://mosquitto.org/files/   binary是編譯好的,source是源碼安裝須要的(make & make install 就行)

惟 一要配置的就是在解壓後的config.mk,安裝完後設置文件是mosquitto.conf

固然主要是設置是否支持ssl,還有就是config.mk最下面的安裝位置的設定。這裏一切默認。

默認啓動是綁定的IP是本地IP,端口是1883能夠在mosquitto.conf裏設置(要去掉前面的#字註釋),linux 中 -c 能夠指定設置文件並運行

比 如: mosquitto -c /etc/mosquitto.conf

相關文章
相關標籤/搜索