MQTT協議從服務端到客戶端詳解

weixin_34194087發表於2018-03-09

一:前言

       最近在瞭解MQTT協議相關的內容,內容有點多,特此把MQTT協議,以及其從服務端到客戶端的流程整理出來,記錄如下。

二:MQTT協議介紹

        MQTT(Message Queuing Telemetry Transport,訊息佇列遙測傳輸)是IBM開發的一個即時通訊協議,它是一種輕量級的、基於代理的“釋出/訂閱”模式的訊息傳輸協議。其具有協議簡潔小巧可擴充套件性強省流量省電等優點,而且已經有PHP,JAVA,Python,C,C#,Go等多個語言版本,基本可以使用在任何平臺上,幾乎可以把所有聯網物品和外部連線起來,所以特別適合用來當做物聯網的通訊協議,實用的場景有遙感資料、汽車、智慧家居、智慧城市、醫療醫護等等。

MQTT特點

        MQTT協議是為大量計算能力有限,且工作在低頻寬不可靠的網路的遠端感測器和控制裝置通訊而設計的協議,它具有以下主要的幾項特性:

1、使用釋出/訂閱訊息模式,提供一對多的訊息釋出,解除應用程式耦合;

2、對負載內容遮蔽的訊息傳輸;

3、使用 TCP/IP 提供網路連線;

4、有三種訊息釋出服務質量:

        “至多一次”,訊息釋出完全依賴底層 TCP/IP 網路。會發生訊息丟失或重複。這一級別可用於如下情況,環境感測器資料,丟失一次讀記錄無所謂,因為不久後還會有第二次傳送。

        “至少一次”,確保訊息到達,但訊息重複可能會發生。

        “只有一次”,確保訊息到達一次。這一級別可用於如下情況,在計費系統中,訊息重複或丟失會導致不正確的結果。

5、小型傳輸,開銷很小(固定長度的頭部是 2 位元組),協議交換最小化,以降低網路流量;

6、使用 Last Will (遺囑)和 Testament 特性通知有關各方客戶端異常中斷的機制;

MQTT協議內容

1 :訊息模型

        MQTT是一種基於代理的釋出/訂閱的訊息協議。與請求/回答這種同步模式不同,釋出/訂閱模式解耦了釋出訊息的客戶(釋出者)與訂閱訊息的客戶(訂閱者)之間的關係,這意味著釋出者和訂閱者之間並不需要直接建立聯絡。一個釋出者可以對應多個訂閱者,當釋出者發生變化的時候,他可以將訊息一一通知給所有的訂閱者。這種模式提供了更大的網路擴充套件性和更動態的網路拓撲

5210585-2f3b0a8548472bb2.png

       此外運用MQTT協議,裝置可以很方便地連線到物聯網雲服務,管理裝置並處理資料,最後應用到各種業務場景,如下圖所示

5210585-3439e4679ba5377d.png

2 服務質量

        MQTT提供三種質量的服務:

         至多一次(qos = 0),可能會出現丟包的現象。使用在對實時性要求不高的情況。這一級別可應用於如下情景,如環境感測器資料,丟失一次讀記錄無所謂,因為很快下一次讀記錄就會產生。

        至少一次(qos = 1),保證包會到達目的地,但是可能出現重包。

        正好一次(qos = 2),保證包會到達目的地,且不會出現重包的現象。這一級別可用於如計費系統等場景,在計費系統中,訊息丟失或重複可能會導致生成錯誤的費用。

5210585-9a7d90aca2ed4b73.png
服務質量

3 主題與萬用字元

        主題名稱(Topic name)用來標識已釋出訊息的資訊的渠道。訂閱者用它來確定接收到所關心的資訊。它是一個分層的結構,用斜線“/”作為分隔符(這個有點類似於restful風格)。主題還可以通過萬用字元進行過濾。其中,+可以過濾一個層級,而#只能出現在主題最後表示過濾任意級別的層級。值得注意的是MQTT允許使用萬用字元訂閱主題,但是並不允許使用萬用字元廣播

舉個例子:

building-b/floor-5:代表B樓5層的裝置。

+/floor-5:代表任何一個樓的5層的裝置。

building-b/#:代表B樓所有的裝置。

4 遺囑

        當一個客戶端斷開連線的時候,它希望客戶端可以傳送它指定的訊息。該訊息和普通訊息的結構相同。通過設定該位並填入和資訊相關的內容即可(後面會有介紹)。

5 訊息型別

訊息型別    型別    編碼說明

reserved       0        保留

connect        1         客戶端到服務端的連線請求

connACK     2          服務端對連線請求的響應

publish         3           釋出訊息

puback         4           新發布訊息確認,是QoS 1給PUBLISH訊息的回覆

pubRec        5           QoS 2訊息流的第一部分,表示訊息釋出已記錄

pubRel          6           QoS 2訊息流的第二部分,表示訊息釋出已釋放

pubComp      7           QoS 2訊息流的第三部分,表示訊息釋出完

subscribe      8           客戶端訂閱某個主題

subBack        9           對於SUBSCRIBE訊息的確認

unsubscribe 10           客戶端終止訂閱的訊息

unsubBack   11       對於UNSUBSCRIBE訊息的確認

pingReq        12       心跳

pingResp      13        確認心跳

disconnect    14        客戶端終止連線前通知MQTT代理

reserved        15        保留

MQTT協議頭部資訊詳細介紹

        客戶端釋出訊息經由伺服器分發到所有對應的訂閱者那裡。一個訂閱者可以訂閱若干個主題(Topic name),但一個PUBLISH訊息只能擁有一個主題。其訊息架構如下:

5210585-d03e1693e883f0ec.png

1 固定頭部

        固定頭部,使用兩個位元組,共16位:

5210585-32caadd9919c338d.png

Byte 1 訊息型別和標誌欄位,訊息型別(4-7),使用4位二進位制表示,可代表16種訊息型別。

Byte 2 剩餘長度欄位(至少1個位元組,最多4個位元組),採用big-endian模式儲存。

訊息型別前面已有介紹 此處附上一張圖:

5210585-5809c8cd87c30861.png

DUP flag(開啟標誌)

保證訊息可靠傳輸,預設為0,只佔用一個位元組,表示第一次傳送。不能用於檢測訊息重複傳送等。適用於客戶端或伺服器端嘗試重發PUBLISH(傳送訊息), PUBREL(QoS 2訊息流的第二部分,表示訊息釋出已釋放), SUBSCRIBE(客戶端訂閱某個主題) 或 UNSUBSCRIBE(客戶端終止訂閱的訊息)訊息,注意需要滿足以下條件:當 QoS > 0時訊息需要回復確認,此時,在可變頭部需要包含訊息ID。當值為1時,表示當前訊息先前已經被傳送過。

QoS(Quality of Service,服務質量)

使用兩個二進位制表示PUBLISH型別訊息:

5210585-03bfa550f1e3116b.png

RETAIN(保持)

僅針對PUBLISH訊息。不同值,不同含義:

0:僅僅為當前訂閱者推送此訊息。

1:表示傳送的訊息需要一直持久儲存(不受伺服器重啟影響),不但要傳送給當前的訂閱者,並且以後新來的訂閱了此Topic name的訂閱者會馬上得到推送。

另外對於新加入的訂閱者,只會取出最新的一個RETAIN flag = 1的訊息推送。

Remaining Length(剩餘長度)

在當前訊息中剩餘的byte(位元組)數,包含可變頭部和負荷(稱之為內容/body,更為合適)。單個位元組最大值:01111111,16進位制:0x7F,10進製為127。單個位元組為什麼不能是11111111(0xFF)呢?因為MQTT協議規定,第八位(最高位)若為1,則表示還有後續位元組存在。

同時MQTT協議最多允許4個位元組表示剩餘長度。那麼最大長度為:0xFF,0xFF,0xFF,0x7F。

二進位制表示為:11111111,11111111,11111111,01111111

十進位制:268435455 byte=261120KB=256MB=0.25GB

四個位元組之間值的範圍:

5210585-f8a84b34c4e5dc44.png

2 可變頭部

        固定頭部僅定義了訊息型別和一些標誌位,一些訊息的後設資料,需要放入可變頭部中。可變頭部內容位元組長度 + Payload/負荷位元組長度 = 剩餘長度,這個是需要牢記的。可變頭部,包含了協議名稱,版本號,連線標誌,使用者授權,心跳時間等內容,這些在後面會講到。

5210585-1ce819bba435a205.png

3 Payload/訊息體/負荷

訊息體主要是為配合固定/可變頭部命令(比如CONNECT可變頭部User name標記若為1則需要在訊息體中附加使用者名稱稱字串)而存在。

CONNECT/SUBSCRIBE/SUBACK/PUBLISH等訊息有訊息體。PUBLISH的訊息體以二進位制形式對待。

請記住MQTT協議只允許在PUBLISH型別訊息體中使用自定義特性,在固定/可變頭部想加入自定義私有特性,就免了吧。這也是為了協議免於流於形式,變得很分裂也為了兼顧現有客戶端等。比如支援壓縮等,那就可以在Payload中定義資料支援,在應用中進行讀取處理

4 訊息識別符號/訊息ID

        一個16位無符號位的short型別值(值不能為 0,0做保留作為無效的訊息ID),僅僅要求在一個特定方向(伺服器發往客戶端為一個方向,客戶端傳送到伺服器端為另一個方向)的通訊訊息中必須唯一。比如客戶端發往伺服器,有可能存在伺服器發往客戶端會同時存在重複,但不礙事。

可變頭部中,需要兩個位元組的順序是MSB(Most Significant Bit) LSB(Last/Least Significant Bit),翻譯成中文就是,最高有效位,最低有效位。最高有效位在最低有效位左邊/上面,表示這是一個大端位元組/網路位元組序,符合人的閱讀習慣,高位在最左邊。

5210585-0034f7d0be07cf19.png

MQTT協議連線和心跳介紹

 CONNECT

TCP連線建立完畢後,Client向Server發出一個Request。

如果一段時間內接收不到Server的Response,則關閉socket,重新建立一個session連線。

如果一個ClientID已經與伺服器連線,則持有同樣ClientID的舊有連線必須由伺服器關閉後,新建立才能建立。下面是一個較為完整的CONNECT訊息結構:

5210585-ef0624c294c40b35.png

下面介紹Connect Flags相關的引數

1 連線標誌(Connect Flags)

一個位元組表示,除了第1位是保留未使用,其它7位都具有不同含義。業務上很重要,對訊息總體流程影響很大,需要牢記。

2 Clean Session

0,表示如果訂閱的客戶機斷線了,要儲存為其要推送的訊息(QoS為1和QoS為2),若其重新連線時,需將這些訊息推送(若客戶端長時間不連線,需要設定一個過期值)。 1,斷線伺服器即清理相關資訊,重新連線上來之後,會再次訂閱。

3 Will Flag

定義了客戶端(沒有主動傳送DISCONNECT訊息)出現網路異常導致連線中斷的情況下,伺服器需要做的一些措施。

簡而言之,就是客戶端預先定義好,在自己異常斷開的情況下,所留下的最後遺願(Last Will),也稱之為遺囑(Testament)。 這個遺囑就是一個由客戶端預先定義好的主題和對應訊息,附加在CONNECT的可變頭部中,在客戶端連線出現異常的情況下,由伺服器主動釋出此訊息。

只有在Will Flag位為1時,Will Qos和Will Retain才會被讀取,此時訊息體payload中要出現Will Topic和Will Message具體內容,否則,Will QoS和Will Retain值會被忽略掉。

4 Will Qos

兩位表示,和PUBLISH訊息固定頭部的QoS level含義一樣。這裡先略過,到PUBLISH訊息再回過頭來看看,會更明白些。若標識了Will Flag值為1,那麼Will QoS就會生效,否則會被忽略掉。

5 Will Retain

如果設定Will Flag,Will Retain標誌就是有效的,否則它將被忽略。當客戶端意外斷開伺服器釋出其Will Message之後,伺服器是否應該繼續儲存。這個屬性和PUBLISH固定頭部的RETAIN標誌含義一樣,這裡先略過。

6 User name 和 password Flag

用於授權,兩者要麼為0要麼為1,否則都是無效。都為0,表示客戶端可自由連線/訂閱,都為1,表示連線/訂閱需要授權。

CONNACK

收到CONNECT訊息之後,伺服器應該返回一個CONNACK訊息作為響應:

若客戶端繞過CONNECT訊息直接傳送其它型別訊息,伺服器應關閉此非法連線 若客戶端傳送CONNECT之後未收到CONNACT,需要關閉當前連線,然後重新連線

相同Client ID客戶端已連線到伺服器,先前客戶端必須斷開連線後,伺服器才能完成新的客戶端CONNECT連線 客戶端傳送無效非法CONNECT訊息,伺服器需要關閉。

一個完整的CONNACK訊息大致如下:

5210585-4be173333b38b048.png

PUBLISH 釋出訊息

  Client/Servier均可以進行PUBLISH。(這裡的server指的是MQTT的中介軟體服務,例如:下面會講到的Apollo,Mosquitto 等伺服器)

  publish message 應該包含一個TopicName(Subject/Channel),即訂閱關鍵詞。

  具體的互動下面這張圖就描述的很清晰了:

5210585-7fc43af062b8015c.jpg

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釋出類似過程確認。

PUBREC字面意思為Assured publish received,作為訂閱者/伺服器對QoS level = 2的釋出PUBLISH訊息的傳送方的響應,確認已經收到,為QoS level = 2訊息流的第二個訊息。 和PUBACK相比,除了訊息型別不同外,其它都是一樣

 PUBREL  Qos level = 2的協議流的第三個訊息,有PUBLISH訊息的釋出者傳送,參與方接收。完整示範如下

 PUBCOMP  作為QoS level = 2訊息流第四個,也是最後一個訊息,由收到PUBREL的一方向另一方做出的響應訊息。完整的訊息一覽,和PUBREL一致,除了訊息型別。

PINGREQ / PINGRES 心跳

Client有責任傳送KeepAliveTime時長告訴給Server(表明當前client處於活動狀態)。在一個時長內,傳送PINGREQ,Server傳送PINGRES確認。

Server在1.5個時長內未收到PINGREQ,就斷開連線。

Client在1個時長內未收到PINGRES,斷開連線。

一般來說,時長設定為幾個分鐘。最大18小時,0表示一直未斷開。

心跳時間(Keep Alive timer)

以秒為單位,定義伺服器端從客戶端接收訊息的最大時間間隔。一般應用服務會在業務層次檢測客戶端網路是否連線,不是TCP/IP協議層面的心跳機制(比如開啟SOCKET的SO_KEEPALIVE選項)。 一般來講,在一個心跳間隔內,客戶端傳送一個PINGREQ訊息到伺服器,伺服器返回PINGRESP訊息,完成一次心跳互動,繼而等待下一輪。若客戶端沒有收到心跳反饋,會關閉掉TCP/IP埠連線,離線。 16位兩個位元組,可看做一個無符號的short型別值。最大值,2^16-1 = 65535秒 = 18小時。最小值可以為0,表示客戶端不斷開。一般設為幾分鐘,比如微信心跳週期為300秒

連線異常中斷通知機制

CONNECT訊息一旦設定在可變頭部設定了Will flag標記,那就啟用了Last-Will-And-Testament特性,此特性很贊。

一旦客戶端出現異常中斷,便會觸發伺服器釋出Will Message訊息到Will Topic主題上去,通知Will Topic訂閱者,對方因異常退出。

抓包分析頭部資料

前面說了這麼多都是概念性的東西,下面我來點實際性的操作,用wireshark抓包看看具體的MQTT協議資料到底長成什麼樣,加深對前面概念的理解

我這裡用的是wireshark+paho(gui)這兩個工具,borker使用的是mosquitto。順便提下paho是eclipse下的一個子專案,它只是一個庫,官網貌似並不提供gui版本(圖形介面),我這裡是從github上下載的原始碼進行編譯得到的介面版本,這個介面對於MQTT的訊息除錯還是蠻好用的,有興趣的也可以試下,專案的github地址:https://github.com/eclipse/paho.mqtt.java

最新版的wireshark已經支援mqtt協議了,所以在過濾其裡面直接填入 mqtt 就可以過濾到mqtt協議的請求了

5210585-c072be24bfb98da6.png

可以看到上面圖中已經抓到我在paho中發起建立連線的請求了,並且在info那一欄可以清楚的看到 connect command,我們再看下下面的具體資料包,它顯示的是原始是16進位制的,10 1e 00 04 4d 51 54 54 04 02 00 3c 00 12 70 61 68 6f 31 31 31 35 37 37 32 31 39 34 33 36 30 33 這麼一大串,下面這張圖就解釋的比較清楚了

5210585-a6c4e75885a311ae.png

我們來分析下這個資料包,前面兩個位元組是10和1e

第一個位元組:0x10對應的2進位制是 10000,用8位bit來顯示就是 0001 0000 ,上圖詳細的顯示了這8位的四個部分都是幹什麼用的,這裡就不再詳細介紹了

第二個位元組:0x1e 表示剩餘長度,也就是說本次請求資料包中第二個位元組後面所有的位元組總數,0x1e換算成十進位制就是1*16+14=30位元組, “00 04 4d 51 54 54 04 02 00 3c 00 12 70 61 68 6f 31 31 31 35 37 37 32 31 39 34 33 36 30 33”

可變頭部,再次放圖如下:

5210585-67dd668c13519d06.png

三 :MQTT 服務端(實現MQTT協議的中介軟體)

MQTT協議服務端:https://github.com/mqtt/mqtt.github.io/wiki/servers

MQTT協議類庫(Client):https://github.com/mqtt/mqtt.github.io/wiki/libraries

MQTT協議官網:http://mqtt.org/

    MQTT協議有很多開源的broker可以用,這裡我整理了兩個,分別是Apollo和mosquito;詳細的服務端選擇可以去上面的服務端連結中選。以下所講的環境配置和伺服器搭建都是在MAC環境上,其他平臺的可以參見選用broker的詳細文件。

一:Apollo-Broker搭建

Apache Apollo是一個代理伺服器,其是在ActiveMQ基礎上發展而來的,可以支援多種協議,如:STOMP、AMQP、MQTT、SSL等。其搭建流程如下:

1 配置JAVA_HOME,Apollo是java語言編寫的,因此搭建Apollo-Broker需要java環境,MAC下如何配置JAVA_HOME可自行查閱網上資料。

2下載Apollo

此處由於之針對自己macbook而言選擇OS X版本下載

將下載好的檔案解壓到適當的目錄(最好單獨新建一個方便後續整理)。解壓後會有apache-apollo-xxx資料夾,該資料夾預設為環境變數${APOLLO_HOME};

3 建立broker,有兩種方式

cd放置broker路徑(建議就放在2建立的資料夾中方便以後檢視或整理)

方法一:通過環境變數 (相對路徑)建立${APOLLO_HOME}/bin/apollo create MyBroker //上面是通過環境變數直接建立,如果失敗說明之前操作有些問題導致環境變數配置失敗。

 方法二:將apollo拖入終端用絕對地址 建立 xxx/bin/apollo create MyBroker#在當前目錄下生成一個mqtt_test目錄,其下面包含:*****執行結果******* Creating apollo instance at: MyBroker Generating ssl keystore... You can now start the broker by executing:"/Users/lqx/Desktop/未命名資料夾/MyBroker/bin/apollo-broker"run Or you can run the brokerinthe background using:"/Users/lqx/Desktop/未命名資料夾/MyBroker/bin/apollo-broker-service"start

成功後檔案目錄大致應該是這個樣子:

bin 執行指令碼

etc 環境配置

data 儲存持久化資料

log 執行日誌

tmp 臨時檔案

4 執行broker 

cd MyBroker(3建立的資料夾)

apollo-broker run

5210585-702d60c81b30bb47.png

由於apollo提供了視覺化web介面(這也就是我選擇他的原因),我們在瀏覽器中輸入

http://127.0.0.1:61680/(http訪問) 或者https://127.0.0.1:61681/(https訪問,可用於研究mqtt+ssl)輸入使用者名稱密碼即可登入(預設使用者名稱:admin 密碼:password)

5210585-3e2419491a8ad7ba.png

關於伺服器與客戶端的聯調 ,我會在客戶端篇講到。

值得注意的是 預設配置的tcp的port是61613,我之前寫demo 的時候客戶端一直連不上broker,原因就是伺服器所在主機的埠號61613沒開啟,所以大家在搭建完伺服器後一定要檢查相應的埠是否開啟了,相應埠截圖如下

5210585-d2c8fe33c638063a.png

再說一下Mac的埠情況,目前OSX 10.10之前版本可以用以下指令開放埠

sudo ipfw add 61613 allow tcp from any to any dst-port 61613;

osx10.10之後的版本目前還沒找到開放埠的方法,有知道的可以告訴我一下,查閱資料得到的處理方式都是用Nginx伺服器做埠轉發,不過比較麻煩,所以我用了一個簡單的方法替換了,方法如下:

Mac端預設的tcp埠開放了1883,這個大家可以在網路實用工具中看,所以我們得去吧Apollobroker的配置檔案中的tcpport 由61613改成1883,

在你上面建立好的broker資料夾中找到apollo.xml,這個就是配置檔案

5210585-ce5ef994514b168c.png

將tcp 配置port改成1883

5210585-8f60666fb539250d.png

然後重啟服務就可以了。其他系統可直接開放61613埠號,方便快捷。

apollo 除了提供了視覺化Web介面外,還提供了測試網頁,


5210585-be1dff77181157ee.png

開啟頁面如下

5210585-c8aef32f11d15358.png

在連線後 可以去Apollo監控頁面(http://127.0.0.1:61680/(http訪問) 或者https://127.0.0.1:61681/(https訪問,可用於研究mqtt+ssl))檢視,會發現有你連線的主題和消費者。


5210585-b9a953832674b61d.png

至此,Apollo 相關的伺服器需要講得已經講完了。

二:mosquito 伺服器搭建

Mosquitto是一款實現了 MQTT v3.1 協議的開源訊息代理軟體,提供輕量級的,支援釋出/訂閱的的訊息推送模式,使裝置對裝置之間的短訊息通訊簡單易用

Mosquitto是C語言實現的,不需要配置什麼環境,我們直接用homebrew安裝,簡單快捷。

1 開啟終端 輸入brew install mosquitto直接安裝

Linux(ubuntu)環境下的安裝也比較簡單(注意#號,需要root許可權):

# apt install mosquitto

當然如果真的是這麼安裝的,那麼不好意思,安裝的版本可能會比較低,不過也不要緊,照樣可以用。但是如果你想安裝最新版的,那麼就按照下面的命令來吧:

1、先刪除剛剛安裝mosquitto(沒有安裝的可以直接跳到第2步)

# apt-get --purge remove mosquitto

2、引入mosquitto倉庫並更新

# apt-add-repository ppa:mosquitto-dev/mosquitto-ppa

# apt-get update

3、安裝Mosquitto

# apt-get install mosquitto

4、檢查是否安裝成功

# service mosquitto status

安裝成功介面如下

5210585-af8ce8002ab5919c.png

mosquitto服務啟動命令

停止服務  brew services stop mosquitto

啟動服務  brew services start mosquitto

重啟服務  brew services restart mosquitto

接下來講一下mosquito的配置檔案,配置檔案是目錄/usr/local/etc/mosquitto/下的mosquitto.conf檔案。配置檔案相關說明如下,

# =================================================================    

# General configuration    

# =================================================================    


# 客戶端心跳的間隔時間    

#retry_interval 20    


# 系統狀態的重新整理時間    

#sys_interval 10    


# 系統資源的回收時間,0表示儘快處理    

#store_clean_interval 10    


# 服務程式的PID    

#pid_file /var/run/mosquitto.pid    


# 服務程式的系統使用者    

#user mosquitto    


# 客戶端心跳訊息的最大併發數    

#max_inflight_messages 10    


# 客戶端心跳訊息快取佇列    

#max_queued_messages 100    


# 用於設定客戶端長連線的過期時間,預設永不過期    

#persistent_client_expiration    


# =================================================================    

# Default listener    

# =================================================================    


# 服務繫結的IP地址    

#bind_address    


# 服務繫結的埠號    

#port 1883    


# 允許的最大連線數,-1表示沒有限制    

#max_connections -1    


# cafile:CA證照檔案    

# capath:CA證照目錄    

# certfile:PEM證照檔案    

# keyfile:PEM金鑰檔案    

#cafile    

#capath    

#certfile    

#keyfile    


# 必須提供證照以保證資料安全性    

#require_certificate false    


# 若require_certificate值為true,use_identity_as_username也必須為true    

#use_identity_as_username false    


# 啟用PSK(Pre-shared-key)支援    

#psk_hint    


# SSL/TSL加密演算法,可以使用“openssl ciphers”命令獲取    

# as the output of that command.    

#ciphers    


# =================================================================    

# Persistence    

# =================================================================    


# 訊息自動儲存的間隔時間    

#autosave_interval 1800    


# 訊息自動儲存功能的開關    

#autosave_on_changes false    


# 持久化功能的開關    

persistencetrue    


# 持久化DB檔案    

#persistence_file mosquitto.db    


# 持久化DB檔案目錄    

#persistence_location /var/lib/mosquitto/    


# =================================================================    

# Logging    

# =================================================================    


# 4種日誌模式:stdout、stderr、syslog、topic    

# none 則表示不記日誌,此配置可以提升些許效能    

log_dest none    


# 選擇日誌的級別(可設定多項)    

#log_type error    

#log_type warning    

#log_type notice    

#log_type information    


# 是否記錄客戶端連線資訊    

#connection_messages true    


# 是否記錄日誌時間    

#log_timestamp true    


# =================================================================    

# Security    

# =================================================================    


# 客戶端ID的字首限制,可用於保證安全性    

#clientid_prefixes    


# 允許匿名使用者    

#allow_anonymous true    


# 使用者/密碼檔案,預設格式:username:password    

#password_file    


# PSK格式密碼檔案,預設格式:identity:key    

#psk_file    


# pattern write sensor/%u/data    

# ACL許可權配置,常用語法如下:    

# 使用者限制:user     

# 話題限制:topic [read|write]     

# 正則限制:pattern write sensor/%u/data    

#acl_file    


# =================================================================    

# Bridges    

# =================================================================    


# 允許服務之間使用“橋接”模式(可用於分散式部署)    

#connection     

#address [:]    

#topic  [[[out | in | both] qos-level] local-prefix remote-prefix]    


# 設定橋接的客戶端ID    

#clientid    


# 橋接斷開時,是否清除遠端伺服器中的訊息    

#cleansession false    


# 是否釋出橋接的狀態資訊    

#notifications true    


# 設定橋接模式下,訊息將會發布到的話題地址    

# $SYS/broker/connection//state    

#notification_topic    


# 設定橋接的keepalive數值    

#keepalive_interval 60    


# 橋接模式,目前有三種:automatic、lazy、once    

#start_type automatic    


# 橋接模式automatic的超時時間    

#restart_timeout 30    


# 橋接模式lazy的超時時間    

#idle_timeout 60    


# 橋接客戶端的使用者名稱    

#username    


# 橋接客戶端的密碼    

#password    


# bridge_cafile:橋接客戶端的CA證照檔案    

# bridge_capath:橋接客戶端的CA證照目錄    

# bridge_certfile:橋接客戶端的PEM證照檔案    

# bridge_keyfile:橋接客戶端的PEM金鑰檔案    

#bridge_cafile    

#bridge_capath    

#bridge_certfile    

#bridge_keyfile    

mosquito 配置使用者名稱和密碼可以參考https://www.jianshu.com/p/4b545332b495這篇簡書,我這裡做一個簡單demo就不配置使用者名稱和密碼了。

我們需要改的配置很少

5210585-57a1b40100b88de7.png

就設定一下host 和port就可以了。配置好後重啟服務就可以生效了。

要注意的地方和Apollo一樣 ,注意埠號是否開啟或被佔用。

由於mosquito沒有提供視覺化介面,在自己不搭建視覺化介面的情況下,我們可以用兩個客戶端訂閱同一主題來測試mosquito伺服器。mosquito至此就基本ok了。

四  MQTT客戶端

客戶端一般兩個常用的mqtt三方庫MQTTKit和MQTTClient,MQTTClient在Ios10出來後更新了一版,經常維護;MQTTKit,這個貌似很久沒更新了,所以我們選用MQTTClient,搭建環境為iOS。

1 安裝MQTTClient

直接用cocopod整合  pod 'MQTTClient'

2相關類

5210585-24af7d861ea8d8e7.png

3 具體用法 

5210585-1fbaec52377c3161.png

這裡做連線的時候 需要先開啟你的服務,用mosquito或者Apollo都可以 

用Apollo 是需要加使用者名稱和密碼的,預設為admin 和password ,用mosquito則不需要使用者名稱和密碼。host為你伺服器的ip,port為你設定的port 我這邊是1883,伺服器所在主機和手機在同一區域網內就可以連上,覺得區域網麻煩的大佬可以直接甩到阿里雲之類的伺服器上去。連上後,訂閱同一主題的客戶端就能相互通訊了,比如在Apollo 伺服器下手機客戶端可以和其提供的webdemo通訊了。

客戶端接受訊息

5210585-d1a12ece86e32c83.png

客戶端傳送訊息

5210585-c3f65faaa343450f.png

其他多主題訂閱 或者lastwill遺囑設定或者retain設定參考MQTTClient的註釋。

最後 用完後記得釋放資源

5210585-d3e06c067fe7529b.png

至此,一個簡單的MQTT協議從服務端到客戶端的實現到此就完成了,歡迎大家補充完善。

能讀到這裡我很佩服你的耐心,壯士請...留...步...,點個讚唄

相關文章