工業(yè)物聯(lián)網(wǎng)核心技術(shù)——MQTT(二)
接上篇《工業(yè)物聯(lián)網(wǎng)核心技術(shù)——MQTT(一)》
三、MQTT的安全
由于MQTT運(yùn)行于TCP層之上并以明文方式傳輸,這就相當(dāng)于HTTP的明文傳輸,使用Wireshark可以完全看到MQTT發(fā)送的所有消息,消息指令一覽無(wú)遺,如圖1所示。
圖1 Wireshark抓取MQTT數(shù)據(jù)包
這樣可能會(huì)產(chǎn)生以下風(fēng)險(xiǎn):
- 設(shè)備可能會(huì)被盜用;
- 客戶端和服務(wù)端的靜態(tài)數(shù)據(jù)可能是可訪問(wèn)的(可能會(huì)被修改);
- 協(xié)議行為可能有副作用;
- 通信可能會(huì)被攔截、修改、重定向或者泄露;
- 虛假控制報(bào)文注入。
作為傳輸協(xié)議,MQTT僅關(guān)注消息傳輸,提供合適的安全功能是開(kāi)發(fā)者的責(zé)任。安全功能可以從三個(gè)層次來(lái)考慮——應(yīng)用層、傳輸層、網(wǎng)絡(luò)層。
- 應(yīng)用層:在應(yīng)用層上,MQTT提供了客戶標(biāo)識(shí)(Client Identifier)以及用戶名和密碼,可以在應(yīng)用層驗(yàn)證設(shè)備。
- 傳輸層:類似于HTTPS,MQTT基于TCP連接,也可以加上一層TLS,傳輸層使用TLS加密是確保安全的一個(gè)好手段,可以防止中間人攻擊。客戶端證書(shū)不但可以作為設(shè)備的身份憑證,還可以用來(lái)驗(yàn)證設(shè)備。
- 網(wǎng)絡(luò)層:如果有條件的話,可以通過(guò)拉專線來(lái)連接設(shè)備與MQTT代理,以提高網(wǎng)絡(luò)傳輸?shù)陌踩浴?/li>
1. 認(rèn)證
MQTT支持兩種層次的認(rèn)證:
- 應(yīng)用層:MQTT支持客戶標(biāo)識(shí)、用戶名和密碼認(rèn)證;
- 傳輸層:傳輸層可以使用TLS,除了加密通訊,還可以使用X509證書(shū)來(lái)認(rèn)證設(shè)備。
2. 客戶標(biāo)識(shí)
MQTT客戶端可以發(fā)送最多65535個(gè)字符作為客戶標(biāo)識(shí)(Client Identifier),一般來(lái)說(shuō)可以使用嵌入式芯片的MAC地址或者芯片序列號(hào)。雖然使用客戶標(biāo)識(shí)來(lái)認(rèn)證可能不可靠,但是在某些封閉環(huán)境或許已經(jīng)足夠了。
3. 用戶名和密碼
MQTT協(xié)議支持通過(guò)CONNECT消息的username和password字段發(fā)送用戶名和密碼。
用戶名及密碼的認(rèn)證使用起來(lái)非常方便,不過(guò)由于它們是以明文形式傳輸,所以使用抓包工具就可以輕易的獲取。
一般來(lái)說(shuō),使用客戶標(biāo)識(shí)、用戶名和密碼已經(jīng)足夠了,比如支持MQTT協(xié)議連接的OneNET云平臺(tái),就是使用了這三個(gè)字段作為認(rèn)證。如果感覺(jué)還不夠安全,還可以在傳輸層進(jìn)行認(rèn)證。
4. 在傳輸層認(rèn)證
在傳輸層認(rèn)證是這樣的:MQTT代理在TLS握手成功之后可以繼續(xù)發(fā)送客戶端的X509證書(shū)來(lái)認(rèn)證設(shè)備,如果設(shè)備不合法便可以中斷連接。使用X509認(rèn)證的好處是,在傳輸層就可以驗(yàn)證設(shè)備的合法性,在發(fā)送CONNECT消息之前便可以阻隔非法設(shè)備的連接,以節(jié)省后續(xù)不必要的資源浪費(fèi)。而且,MQTT協(xié)議運(yùn)行在使用TLS時(shí),除了提供身份認(rèn)證,還可以確保消息的完整性和保密性。
5. 選擇用戶數(shù)據(jù)格式
MQTT協(xié)議只實(shí)現(xiàn)了傳送消息的格式,并沒(méi)有限制用戶協(xié)議需要按照一定的風(fēng)格,因此在MQTT協(xié)議之上,我們需要定義一套自己的通信協(xié)議。比如說(shuō),發(fā)布者向設(shè)備發(fā)布一條打開(kāi)消息,設(shè)備可以回復(fù)一個(gè)消息并攜帶返回碼,這樣的消息格式是使用二進(jìn)制、字符串還是JSON格式呢?下面就簡(jiǎn)單做個(gè)選型參考。
6. 十六進(jìn)制/二進(jìn)制
MQTT原本就是基于二進(jìn)制實(shí)現(xiàn)的,所以用戶協(xié)議使用二進(jìn)制實(shí)現(xiàn)是一個(gè)不錯(cuò)的選擇。雖然失去了直觀的可讀性,但可以將流量控制在非常小。其實(shí)對(duì)于單片機(jī)開(kāi)發(fā)者來(lái)說(shuō)十六進(jìn)制并不陌生,因?yàn)閱纹瑱C(jī)寄存器都是以位來(lái)操作的,芯片間通信也會(huì)使用十六進(jìn)制/二進(jìn)制。而對(duì)于沒(méi)有單片機(jī)開(kāi)發(fā)經(jīng)驗(yàn)的工程師來(lái)說(shuō),十六進(jìn)制/二進(jìn)制可能就太原始了。下面我們繼續(xù)看看還有沒(méi)有其他方案。
7. 字符串
對(duì)單片機(jī)開(kāi)發(fā)者來(lái)說(shuō),字符串也是一個(gè)選擇。比如通過(guò)串口傳輸?shù)腁T指令就是基于字符串通信的。使用字符串方便了人閱讀,但是對(duì)高級(jí)語(yǔ)言開(kāi)發(fā)者來(lái)說(shuō),鍵值對(duì)(Key-Value)才更受歡迎。
四、MQTT好拍檔
1. JSON
JSON中文全稱是JavaScript對(duì)象標(biāo)記語(yǔ)言,在這門(mén)語(yǔ)言中,一切都是對(duì)象。因此,任何支持的類型都可以通過(guò)JSON來(lái)表示,例如字符串、數(shù)字、對(duì)象、數(shù)組等。其語(yǔ)法規(guī)則是:
- 對(duì)象表示為鍵值對(duì);
- 數(shù)據(jù)由逗號(hào)分隔;
- 花括號(hào)保存對(duì)象;
- 方括號(hào)保存數(shù)組。
JSON層次結(jié)構(gòu)簡(jiǎn)潔清晰,易于閱讀和編寫(xiě),同時(shí)也易于機(jī)器解析和生成,有效提升網(wǎng)絡(luò)傳輸效率。
對(duì)于單片機(jī)開(kāi)發(fā)者,主流的微控制器軟件開(kāi)發(fā)工具Keil有提供JSON庫(kù),可以用于STC、STM32等微控制器開(kāi)發(fā),所以在微控制器上解析JSON不需要自己寫(xiě)一個(gè)JSON解析器或者移植了。
如果實(shí)在懶得使用JSON庫(kù)生成或解析,也可以直接使用C語(yǔ)言中的sprintf生成JSON字符串,比如:
- sprintf(buf, "{"String":"%s", "Value":%d}", "Hello World!", 12345);
這樣就可以生成一個(gè){“String”:”Hello World!”, “Value”:12345}JSON字符串了。
2. XML
MQTT協(xié)議只負(fù)責(zé)通信部分,用戶協(xié)議可以自己選擇,當(dāng)然也可以選擇復(fù)雜又冗長(zhǎng)的XML格式。可是既然要選擇MQTT+XML,為什么不考慮換為XMPP呢?
3. 小結(jié)
綜上所述,MQTT+JSON協(xié)議簡(jiǎn)潔清晰、易于閱讀、解析和生成等,也考慮了服務(wù)器端開(kāi)發(fā)者和設(shè)備端開(kāi)發(fā)者的開(kāi)發(fā)成本。
五、有關(guān)MQTT的云平臺(tái)和工具
1. 支持MQTT的云平臺(tái)
目前,百度、阿里、騰訊的云平臺(tái)都逐漸有了物聯(lián)網(wǎng)開(kāi)發(fā)套件:騰訊QQ物聯(lián)平臺(tái)內(nèi)測(cè)中,阿里云物聯(lián)網(wǎng)套件公測(cè)中,兩者都需要進(jìn)行申請(qǐng)?jiān)囉?,而百度云物?lián)網(wǎng)套件已經(jīng)支持MQTT并且可以免費(fèi)試用一段時(shí)間。除了BAT三大家,下面再介紹一些其他支持MQTT的物聯(lián)網(wǎng)云平臺(tái)。
- OneNET云平臺(tái):OneNET是由中國(guó)移動(dòng)打造的PaaS物聯(lián)網(wǎng)開(kāi)放平臺(tái)。平臺(tái)能夠幫助開(kāi)發(fā)者輕松實(shí)現(xiàn)設(shè)備接入與設(shè)備連接,快速完成產(chǎn)品開(kāi)發(fā)部署,為智能硬件、智能家居產(chǎn)品提供完善的物聯(lián)網(wǎng)解決方案。OneNET云平臺(tái)已經(jīng)于2014年10月正式上線。
- 云巴:云巴(Cloud Bus)是一個(gè)跨平臺(tái)的雙向?qū)崟r(shí)通信系統(tǒng),為物聯(lián)網(wǎng)、App和Web提供實(shí)時(shí)通信服務(wù)。云巴基于MQTT,支持Socket.IO協(xié)議,支持RESTful API。
2. MQTT服務(wù)器
如果不想使用云平臺(tái),只是純粹地玩一下MQTT,或者只想在內(nèi)網(wǎng)對(duì)設(shè)備進(jìn)行監(jiān)控,那么可以自己本地部署一個(gè)MQTT服務(wù)器。下面介紹幾款MQTT服務(wù)器:
- Apache-Apollo:一個(gè)代理服務(wù)器,在ActiveMQ基礎(chǔ)上發(fā)展而來(lái),可以支持STOMP、AMQP、MQTT、Openwire、SSL和WebSockets等多種協(xié)議,并且Apollo提供后臺(tái)管理頁(yè)面,方便開(kāi)發(fā)者管理和調(diào)試。
- EMQ:EMQ 2.0,基于Erlang/OTP語(yǔ)言平臺(tái)開(kāi)發(fā),支持大規(guī)模連接和分布式集群,發(fā)布訂閱模式的開(kāi)源MQTT消息服務(wù)器。
- HiveMQ:一個(gè)企業(yè)級(jí)的MQTT代理,主要用于企業(yè)和新興的機(jī)器到機(jī)器M2M通訊和內(nèi)部傳輸,滿足可伸縮性、易管理和安全特性,提供免費(fèi)的個(gè)人版。HiveMQ提供了開(kāi)源的插件開(kāi)發(fā)包。
- Mosquitto:一款實(shí)現(xiàn)了消息推送協(xié)議MQTT v3.1的開(kāi)源消息代理軟件,提供輕量級(jí)的、支持可發(fā)布/可訂閱的消息推送模式。
3. MQTT調(diào)試工具
知道了各大平臺(tái)的MQTT,同時(shí)自己也可以在內(nèi)網(wǎng)部署MQTT服務(wù)器,那接下來(lái)沒(méi)有調(diào)試工具怎么行呢,難道要用自己喜歡的語(yǔ)言編寫(xiě)一個(gè)?當(dāng)然不需要。MQTT調(diào)試工具可以考慮使用HiveMQ的MQTT客戶端——HiveMQ Websockets Client,這是一款基于WebSocket的瀏覽器MQTT客戶端,支持主題訂閱和發(fā)布。
4. MQTT與其他協(xié)議
目前各大平臺(tái)都開(kāi)始支持MQTT協(xié)議,MQTT相比其他協(xié)議有什么優(yōu)勢(shì)呢?物聯(lián)網(wǎng)設(shè)備能不能用其他的協(xié)議呢?下面是MQTT與其他部分協(xié)議的比較,給大家作為參考。
5. MQTT與TCP Socket
雖然MQTT運(yùn)行于TCP層之上,看起來(lái)這兩者之間根本沒(méi)有比較性,但筆者覺(jué)得還是有必要敘述一番,因?yàn)榇蠖鄶?shù)從事硬件或嵌入式開(kāi)發(fā)的工程師,都是直接在TCP層上通信的。從事嵌入式開(kāi)發(fā)工作的人都應(yīng)該知道LwIP,LwIP是一套用于嵌入式系統(tǒng)的開(kāi)放源代碼TCP/IP協(xié)議棧,LwIP在保證嵌入式產(chǎn)品擁有完整的TCP/IP功能的同時(shí),又能保證協(xié)議棧對(duì)處理器資源的有限消耗,其運(yùn)行一般僅需要幾十KB的RAM和40KB左右的ROM。
也就是說(shuō),只要是嵌入式產(chǎn)品使用了LwIP,就支持TCP/IP協(xié)議棧,進(jìn)而可以使用MQTT協(xié)議。
由于TCP協(xié)議有粘包和分包問(wèn)題,所以傳輸數(shù)據(jù)時(shí)需要自定義協(xié)議,如果傳輸?shù)臄?shù)據(jù)報(bào)超過(guò)MSS(報(bào)文段長(zhǎng)度),一定要給協(xié)議定義一個(gè)消息長(zhǎng)度字段,確保接收端能通過(guò)緩沖完整收取消息。一個(gè)簡(jiǎn)單的協(xié)議定義:消息頭部+消息長(zhǎng)度+消息正文。
當(dāng)然,使用MQTT協(xié)議則不需要考慮這個(gè)問(wèn)題,這些MQTT都已經(jīng)處理好了,MQTT最長(zhǎng)可以一次性發(fā)送256MB數(shù)據(jù),不用考慮粘包分包的問(wèn)題。
總之,TCP和MQTT本身并不矛盾,只不過(guò)基于Socket開(kāi)發(fā)需要處理更多的事情,而且大多數(shù)嵌入式開(kāi)發(fā)模塊本身也只會(huì)提供Socket接口供廠家自定義協(xié)議。
6. MQTT與HTTP
HTTP最初的目的是提供一種發(fā)布和接收HTML頁(yè)面的方法,主要用于Web。HTTP是典型的C/S通訊模式:請(qǐng)求從客戶端發(fā)出,服務(wù)端只能被動(dòng)接收,一條連接只能發(fā)送一次請(qǐng)求,獲取響應(yīng)后就斷開(kāi)連接。該協(xié)議最早是為了適用Web瀏覽器的上網(wǎng)瀏覽場(chǎng)景而設(shè)計(jì)的,目前在PC、手機(jī)、Pad等終端上都應(yīng)用廣泛。由于這樣的通信特點(diǎn),HTTP技術(shù)在物聯(lián)網(wǎng)設(shè)備中很難實(shí)現(xiàn)設(shè)備的反向控制,不過(guò)非要實(shí)現(xiàn)也不是不行,下面看一下Web端的例子。
目前,在微博等SNS網(wǎng)站上有海量用戶公開(kāi)發(fā)布的內(nèi)容,當(dāng)發(fā)布者發(fā)布消息,數(shù)據(jù)傳到服務(wù)器更新時(shí),就需要給關(guān)注者盡可能的實(shí)時(shí)更新內(nèi)容。Web網(wǎng)站基于HTTP協(xié)議,使用HTTP協(xié)議探測(cè)服務(wù)器上是否有內(nèi)容更新,就必須頻繁地讓客戶端請(qǐng)求服務(wù)器進(jìn)行確認(rèn)。在瀏覽器中要實(shí)現(xiàn)這種效果,可以使用Comet技術(shù),Comet是基于HTTP長(zhǎng)連接的“服務(wù)器推”技術(shù),主要有兩種實(shí)現(xiàn)模型:基于AJAX的長(zhǎng)輪詢(long-polling)方式和基于Iframe及htmlfile的流(streaming)方式。這兩種技術(shù)模型在這里不詳細(xì)展開(kāi),有興趣的讀者可以查閱相關(guān)資料。
如果要實(shí)現(xiàn)設(shè)備的反向控制,可能就要用到前面提到的Comet技術(shù)。由于需要不斷的請(qǐng)求服務(wù)器,會(huì)導(dǎo)致通信開(kāi)銷非常大,加上HTTP冗長(zhǎng)的報(bào)文頭,在節(jié)省流量上實(shí)在沒(méi)有優(yōu)勢(shì)。
當(dāng)然,如果只是單純地讓設(shè)備定時(shí)上報(bào)數(shù)據(jù)而不做控制,也是可以使用HTTP協(xié)議的。
7. MQTT與XMPP
最有可能與MQTT競(jìng)爭(zhēng)的是XMPP協(xié)議。XMPP(可擴(kuò)展通訊與表示協(xié)議)是一項(xiàng)用于實(shí)時(shí)通訊的開(kāi)放技術(shù),它使用可擴(kuò)展標(biāo)記語(yǔ)言(XML)作為交換信息的基本格式。其優(yōu)點(diǎn)是協(xié)議成熟、強(qiáng)大、可擴(kuò)展性強(qiáng)。目前主要應(yīng)用于許多聊天系統(tǒng)中,在消息推送領(lǐng)域,MQTT和XMPP互相競(jìng)爭(zhēng)。下面列舉MQTT與XMPP各自的特性:
- XMPP協(xié)議基于繁重的XML,報(bào)文體積大且交互繁瑣;而MQTT協(xié)議固定報(bào)頭只有兩個(gè)字節(jié),報(bào)文體積小、編解碼容易;
- XMPP基于JID的點(diǎn)對(duì)點(diǎn)消息傳輸;MQTT協(xié)議基于主題(Topic)發(fā)布訂閱模式,消息路由更為靈活;
- XMPP協(xié)議采用XML承載報(bào)文,二進(jìn)制必須進(jìn)行Base64編碼或其他方式處理;MQTT協(xié)議未定義報(bào)文內(nèi)容格式,可以承載JSON、二進(jìn)制等不同類型報(bào)文,開(kāi)發(fā)者可以針對(duì)性的定義報(bào)文格式;
- MQTT協(xié)議支持消息收發(fā)確認(rèn)和QoS保證,有更好的消息可靠性保證;而XMPP主協(xié)議并未定義類似機(jī)制;
- 在嵌入式設(shè)備開(kāi)發(fā)中大多使用的是C語(yǔ)言開(kāi)發(fā),C語(yǔ)言解析XML是非常困難的。MQTT基于二進(jìn)制實(shí)現(xiàn)且未定義報(bào)文內(nèi)容格式,可以很好的兼顧嵌入式C語(yǔ)言開(kāi)發(fā)者;而XMPP基于XML,開(kāi)發(fā)者需要配合協(xié)議格式,不能靈活開(kāi)發(fā)。
綜上所述,在嵌入式設(shè)備中,由于需要一個(gè)靈巧簡(jiǎn)潔,對(duì)設(shè)備開(kāi)發(fā)者和服務(wù)端開(kāi)發(fā)者都友好的協(xié)議,MQTT比XMPP更具有優(yōu)勢(shì)。
8. MQTT與CoAP
CoAP也是一個(gè)能與MQTT競(jìng)爭(zhēng)的協(xié)議。其模仿HTTP的REST模型,服務(wù)端以URI方式創(chuàng)建資源,客戶端可以通過(guò)GET、PUT、POST、DELETE方式訪問(wèn)這些資源,并且協(xié)議風(fēng)格也和HTTP極為相似,例如一個(gè)設(shè)備有溫度數(shù)據(jù),那么這個(gè)溫度可以被描述為:
- CoAP://:/sensors/temperature
其中為設(shè)備的IP,為端口。
不過(guò),如果使用CoAP可能會(huì)讓物聯(lián)網(wǎng)后臺(tái)的情況變得復(fù)雜,比如MQTT可以實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的IoT架構(gòu):Device + MQTT服務(wù)器 + APP,手機(jī)端或Web端可以直接從MQTT服務(wù)器訂閱想要的主題。而CoAP可能需要這樣的架構(gòu):CoAP + Web + DataBase + App,使用CoAP必須經(jīng)過(guò)DataBase才能轉(zhuǎn)給第三方。
至于CoAP和MQTT孰優(yōu)孰劣,這里不作定論。不過(guò)目前來(lái)說(shuō),CoAP資料還是略少。而且,MQTT除了可以應(yīng)用于物聯(lián)網(wǎng)領(lǐng)域,在手機(jī)消息推送、在線聊天等領(lǐng)域都可以有所作為。
9. 小結(jié)
經(jīng)過(guò)以上的比較,我們可以得出如下結(jié)論:MQTT基于異步發(fā)布/訂閱的實(shí)現(xiàn)解耦了消息發(fā)布者和訂閱者,基于二進(jìn)制的實(shí)現(xiàn)節(jié)省了存儲(chǔ)空間及流量,同時(shí)MQTT擁有更好的消息處理機(jī)制,可以替代TCP Socket一部分應(yīng)用場(chǎng)景。相對(duì)于HTTP和XMPP,MQTT可以選擇用戶數(shù)據(jù)格式,解析復(fù)雜度低,同時(shí)MQTT也可用于手機(jī)推送等領(lǐng)域。手機(jī)作為與人連接的入口,正好建立了人與物的連接,可謂一箭雙雕。當(dāng)然,其他協(xié)議也可以作為一個(gè)輔助的存在,HTTP可以為只需定時(shí)上傳數(shù)據(jù)的設(shè)備服務(wù),CoAP則更適用于非常受限的移動(dòng)通信網(wǎng)絡(luò),表3直觀地展示了上文提到的幾種協(xié)議之間的優(yōu)劣異同。