原文地址:http://dataguild.org/?p=6957
官網地址
emptt: https://developer.emqx.io/docs/broker/v3/cn/guide.html
paho: https://github.com/eclipse/paho.mqtt.python
MQTT英文文檔:MQTT Version 3.1.1
MQTT文檔中文翻譯:Introduction · MQTT協議中文版
教程
- MQTT入門篇:https://link.zhihu.com/?target=http%3A//dataguild.org/%3Fp%3D6817
- MQTT進階篇:https://link.zhihu.com/?target=http%3A//dataguild.org/%3Fp%3D6846
- MQTT安全篇:https://link.zhihu.com/?target=http%3A//dataguild.org/%3Fp%3D6866
- MQTT實戰篇:https://link.zhihu.com/?target=http%3A//dataguild.org/%3Fp%3D6957
安裝
環境:ubuntu18.04
emqx-ubuntu18.04-v3.2.1_amd64.deb 下載地址:https://github.com/emqx/emqx/releases
Python客戶端:https://github.com/eclipse/paho.mqtt.python
常用命令
emqx start # 直接啟動 sudo service emqx start # service 啟動 sudo systemctl start emqx # systemctl 啟動 emqx_ctl status
EMQ 管理控制台功能簡介
如果 EMQ 安裝在本機,則使用瀏覽器打開地址 http://127.0.0.1:18083 ,輸入默認用戶名 admin
與默認密碼 public
,登錄進入 Dashboard。如果忘記了管理控制台密碼,使用 管理命令 重置或新建管理賬號。
topic匹配規則基礎
主題層級分隔符 / : 用於分割主題層級,/分割后的主題,這是消息主題層級設計中很重要的符號。
單層通配符 +: 單層通配符只能匹配一層主題。比如: aaa/+ 可以匹配 aaa/bbb ,但是不能匹配aaa/bbb/ccc。 單獨的+號可以匹配單層的所有推送
多層通配符 #: 多層通配符可以匹配於多層主題。比如: aaa/# 不但可以匹配aaa/bbb,還可以匹配aaa/bbb/ccc/ddd。 也就是說,多層通配符可以匹配符合通配符之前主題層級的所有子集主題。單獨的#匹配所有的消息主題.
簡單的發布訂閱示例
訂閱者
import paho.mqtt.client as mqtt def on_connect(client, userdata, flags, rc): print("Connected with result code " + str(rc)) def on_message(client, userdata, msg): print(msg.topic + " " + str(msg.payload)) client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.connect("192.168.1.54", 1883, 600) client.subscribe('emqtt', qos=0) client.loop_forever()
發布者
import paho.mqtt.client as mqtt def on_connect(client, userdata, flags, rc): print("Connected with result code " + str(rc)) def on_message(client, userdata, msg): print(msg.topic + " " + str(msg.payload)) client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.connect("192.168.1.54", 1883, 600) client.publish('emqtt', payload='Hello,EMQ!', qos=0) client.loop_start()
發布者
import paho.mqtt.client as mqtt HOST = "192.168.44.31" PORT = 1883 def Publish_Message(): client = mqtt.Client() client.username_pw_set(username='admin', password='public') # 用於添加了插件認證方式后 client.connect(HOST, PORT, 60) for x in range(10): Message = "hello" + str(x) client.publish("services", Message, 0) # 發布一個主題為'services',內容為‘hello x’的信息 # time.sleep(10) client.loop_forever() # 保持連接狀態 if __name__ == '__main__': Publish_Message()
發布者,主要內容:publish("topic_name","utf8_message",Qos)
- Qos:0 --> 發送者只發送一次消息,不進行重試,Broker不會返回確認消息。Broker可能沒有接收到消息。(默認)
- Qos:1 --> 發送者最少發送一次消息,確保消息達到Broker,Broker需要返回確認消息PUBACK。Broker可能接收到重復消息。
- Qos:2 --> 使用兩階段確認來保證消息的不丟失和不重復。Broker肯定會接收到消息,且只收到一次。
訂閱者
import paho.mqtt.client as mqtt def on_connect(client, userdata, flags, rc): print("Connected with result code "+str(rc)) # rc表示返回來的狀態值 client.subscribe("services") def on_message(client, userdata, msg): print(msg.topic+" " + ":" + str(msg.payload)) if __name__ == "__main__": client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.username_pw_set(username='admin', password='public') # 用於添加了插件認證方式后 client.connect("192.168.44.31", 1883, 60) client.loop_forever()
訂閱者,信息的產出在msg.payload
rc值代表的含義:
0: Connection successful
1: Connection refused - incorrect protocol version
2: Connection refused - invalid client identifier
3: Connection refused - server unavailable
4: Connection refused - bad username or password
5: Connection refused - not authorised
6-255: Currently unused.
物聯網(Internet of Things,IoT)最近曝光率越來越高。雖然HTTP是網頁的事實標准,不過機器之間(Machine-to-Machine,M2M)的大規模溝通需要不同的模式:之前的請求/回答(Request/Response)模式不再合適,取而代之的是發布/訂閱(Publish/Subscribe)模式。這就是輕量級、可擴展的MQTT(Message Queuing Telemetry Transport)可以施展拳腳的舞台。
MQTT簡介
MQTT是基於二進制消息的發布/訂閱編程模式的消息協議,最早由IBM提出的,如今已經成為OASIS規范。由於規范很簡單,非常適合需要低功耗和網絡帶寬有限的IoT場景,比如:
- 遙感數據
- 汽車
- 智能家居
- 智慧城市
- 醫療醫護
由於物聯網的環境是非常特別的,所以MQTT遵循以下設計原則:
- 精簡,不添加可有可無的功能。
- 發布/訂閱(Pub/Sub)模式,方便消息在傳感器之間傳遞。
- 允許用戶動態創建主題,零運維成本。
- 把傳輸量降到最低以提高傳輸效率。
- 把低帶寬、高延遲、不穩定的網絡等因素考慮在內。
- 支持連續的會話控制。
- 理解客戶端計算能力可能很低。
- 提供服務質量管理。
- 假設數據不可知,不強求傳輸數據的類型與格式,保持靈活性。
運用MQTT協議,設備可以很方便地連接到物聯網雲服務,管理設備並處理數據,最后應用到各種業務場景,如下圖所示:
發布/訂閱模式
與請求/回答這種同步模式不同,發布/訂閱模式解耦了發布消息的客戶(發布者)與訂閱消息的客戶(訂閱者)之間的關系,這意味着發布者和訂閱者之間並不需要直接建立聯系。打個比方,你打電話給朋友,一直要等到朋友接電話了才能夠開始交流,是一個典型的同步請求/回答的場景;而給一個好友郵件列表發電子郵件就不一樣,你發好電子郵件該干嘛干嘛,好友們到有空了去查看郵件就是了,是一個典型的異步發布/訂閱的場景。
熟悉編程的同學一定非常熟悉這種設計模式了,因為它帶來了這些好處:
- 發布者與訂閱者不必了解彼此,只要認識同一個消息代理即可。
- 發布者和訂閱者不需要交互,發布者無需等待訂閱者確認而導致鎖定。
- 發布者和訂閱者不需要同時在線,可以自由選擇時間來消費消息。
主題
MQTT是通過主題對消息進行分類的,本質上就是一個UTF-8的字符串,不過可以通過反斜杠表示多個層級關系。主題並不需要創建,直接使用就是了。
主題還可以通過通配符進行過濾。其中,+可以過濾一個層級,而#只能出現在主題最后表示過濾任意級別的層級。
舉個例子:
- building-b/floor-5:代表B樓5層的設備。
- +/floor-5:代表任何一個樓的5層的設備。
- building-b/#:代表B樓所有的設備。
注意,MQTT允許使用通配符訂閱主題,但是並不允許使用通配符廣播。
服務質量
為了滿足不同的場景,MQTT支持三種不同級別的服務質量(Quality of Service,QoS)為不同場景提供消息可靠性:
- 級別0:盡力而為。消息發送者會想盡辦法發送消息,但是遇到意外並不會重試。
- 級別1:至少一次。消息接收者如果沒有知會或者知會本身丟失,消息發送者會再次發送以保證消息接收者至少會收到一次,當然可能造成重復消息。
- 級別2:恰好一次。保證這種語義肯定會減少並發或者增加延時,不過丟失或者重復消息是不可接受的時候,級別2是最合適的。
服務質量是個老話題了。級別2所提供的不重不丟很多情況下是最理想的,不過往返多次的確認一定對並發和延遲帶來影響。級別1提供的至少一次語義在日志處理這種場景下是完全OK的,所以像Kafka這類的系統利用這一特點減少確認從而大大提高了並發。級別0適合雞肋數據場景,食之無味棄之可惜,就這么着吧。
消息類型
MQTT擁有14種不同的消息類型:
- CONNECT:客戶端連接到MQTT代理
- CONNACK:連接確認
- PUBLISH:新發布消息
- PUBACK:新發布消息確認,是QoS 1給PUBLISH消息的回復
- PUBREC:QoS 2消息流的第一部分,表示消息發布已記錄
- PUBREL:QoS 2消息流的第二部分,表示消息發布已釋放
- PUBCOMP:QoS 2消息流的第三部分,表示消息發布完成
- SUBSCRIBE:客戶端訂閱某個主題
- SUBACK:對於SUBSCRIBE消息的確認
- UNSUBSCRIBE:客戶端終止訂閱的消息
- UNSUBACK:對於UNSUBSCRIBE消息的確認
- PINGREQ:心跳
- PINGRESP:確認心跳
- DISCONNECT:客戶端終止連接前優雅地通知MQTT代理
后面我們會給出具體的例子。
MQTT代理
市面上有相當多的高質量MQTT代理,其中mosquitto是一個開源的輕量級的C實現,完全兼容了MQTT 3.1和MQTT 3.1.1。下面我們就以mosquitto為例演示一下MQTT的使用。環境是百度開放雲的雲服務器以及Ubuntu 14.04.1 LTS,簡單起見MQTT代理和客戶端都安裝在同一台雲服務器上了。
首先SSH到雲服務器,安裝mosquitto以及搭配的客戶端:
apt-get install mosquitto apt-get install mosquitto-clients
現在在雲端模擬雲服務,訂閱某辦公樓5層的溫度作為主題:
mosquitto_sub -d -t 'floor-5/temperature' Received CONNACK Received SUBACK Subscribed (mid: 1): 0
然后另外打開一個SSH連接,模擬溫度計發送溫度消息:
mosquitto_pub -d -t 'floor-5/temperature' -m '15' Received CONNACK Sending PUBLISH (d0, q0, r0, m1, 'floor-5/temperature', ... (2 bytes))
此時回到第一個SSH客戶端可以看到信息已經接收到了,之后便是心跳消息:
Received PUBLISH (d0, q0, r0, m0, 'floor-5/temperature', ... (2 bytes)) 15 Sending PINGREQ Received PINGRESP
需要注意的是mosquitto客戶端默認使用QoS 0,下面我們使用QoS 2訂閱這個主題:
mosquitto_sub -d -q 2 -t 'floor-5/temperature' Received CONNACK Received SUBACK Subscribed (mid: 1): 2
切換到另外SSH連接然后在這個主題里面發送溫度消息:
mosquitto_pub -d -q 2 -t 'floor-5/temperature' -m '15' Received CONNACK Sending PUBLISH (d0, q2, r0, m1, 'floor-5/temperature', ... (2 bytes)) Received PUBREC (Mid: 1) Sending PUBREL (Mid: 1) Received PUBCOMP (Mid: 1)
此時回到第一個SSH客戶端可以看到信息已經接收到了,以及相應的多次握手消息:
Received PUBLISH (d0, q2, r0, m1, 'floor-5/temperature', ... (2 bytes)) Sending PUBREC (Mid: 1) Received PUBREL (Mid: 1) 15 Sending PUBCOMP (Mid: 1)
至此我們初步了解了MQTT的基本知識,祝大家在物聯網的世界里面玩得開心!
WebSockets實現與HTTP網頁交互
MQTT是基於TCP協議實現,基於HTTP的網頁應用便無法與之交互了。為了解決這個問題,許多MQTT代理加上了對WebSockets的支持,可以方便地實現如下場景:
- 顯示設備的實時信息
- 接收報警等推送信息
- 查看設備的歷史消息
目前Ubuntu 14.04.1 LTS自帶的Mosquitto版本比較低,所以我們將使用PPA上的新版本:
apt-add-repository ppa:mosquitto-dev/mosquitto-ppa apt-get update apt-get install mosquitto apt-get install mosquitto-clients
以下實驗是基於已經支持WebSockets的1.4.5版本的Mosquitto。打開WebSockets很簡單,只需要在/etc/mosquitto/mosquitto.conf中添加:
listener 8001 protocol websockets
指定以上配置文件重啟Mosquitto服務之后,便可以通過任意MQTT over WebSockets的界面,比如HiveMQ WebSockets Client Showcase或者MQTT Client Sample來把玩了:
瀏覽器其實是以WebSockets協議與MQTT代理交互的,不但可以完成mosquitto_pub和mosquitto_sub的功能,還可以結合HTML5的特性完成很多有意思的場景。下面我們就來實現溫度感知器的圖形界面。
下面是網頁應用的源代碼,其中用到了Paho JavaScript Client實現了MQTT over WebSockets:
<!DOCTYPE html> <html> <head> <title>Start Page</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script src="mqttws31.js"></script> </head> <body> <label>當前溫度</label> <meter max="100" low="60" high="80" value="30" id="meter"></meter> <script> var client = new Paho.MQTT.Client("host", 8001, "clientId"); client.onMessageArrived = function (msg) { document.querySelector("#meter").value = msg.payloadString; }; client.connect({ onSuccess: function () { client.subscribe("floor-5/temperature"); } }); </script> </body> </html>
代碼非常直觀,在連接到MQTT代理之后便訂閱五樓溫度的主題。當后台感知器發送溫度信息后,比如用MQTT快速入門中提到的命令模擬:
mosquitto_pub -d -q 2 -t 'floor-5/temperature' -m '95'
MQTT安全篇
物聯網的核心是連接萬物,通過交換並分析數據使得生活更舒適與便捷。不過,敏感數據泄露或者設備被非法控制可不是鬧着玩的。比如前段時間國內某著名家電企業的智能洗衣機,使用了某著名電商基於XMPP協議的物聯網平台,不費吹灰之力便被黑客攻破並遠程遙控,給智能家居的發展帶來了一些陰影。究其本質,並不是物聯網技術本身有缺陷,而是在物聯網系統的設計中最基本的安全設計被工程師輕視了,才導致整個系統的崩塌。
在這里我們將介紹為何以及如何運用MQTT提供的安全特性來保證物聯網項目的順利實施。
安全對於幾乎所有的項目都是一個挑戰,對於物聯網項目更是如此:
- 設備安全性與設備可用性之間往往是零和博弈。
- 加密算法需要更多的計算能力,而物聯網設備的性能往往非常有限。
- 物聯網的網絡條件常常要比家庭或者辦公室的網絡條件差許多。
對於以上挑戰,MQTT提供了多個層次的安全特性:
- 網絡層:有條件可以通過拉專線或者使用VPN來連接設備與MQTT代理,以提高網絡傳輸的安全性。
- 傳輸層:傳輸層使用TLS加密是確保安全的一個好手段,可以防止中間人攻擊(Man-In-The-Middle Attack)。客戶端證書不但可以作為設備的身份憑證,還可以用來驗證設備。
- 應用層:MQTT還提供客戶標識(Client Identifier)以及用戶名密碼,在應用層驗證設備。
雖然MQTT提供了多重安全設計,不過世界上並沒有銀彈能夠保障數據的絕對安全,所以應該在設計的時候就把安全放在設計目標之中並擁有相當的優先級,否則上文提到的智能洗衣機就是一個活生生的教訓。
網絡層可以使用專線或者VPN超出了本文的范圍,下面我們結合Mosquitto仔細了解一下傳輸層和應用層的MQTT安全特性。
加密
MQTT是基於TCP的,默認情況通訊並不加密。如果你需要傳輸敏感信息或者對設備進行反控,使用TLS幾乎是必須的。打個比方,如果你在咖啡店用免費Wi-Fi上網,登錄互聯網金融的網站不支持HTTPS傳輸,那么你的賬號信息多半已經在咖啡店的Wi-Fi日志里面躺着了……
TLS是非常成熟的安全協議,在握手的時候便可以創建安全連接,使得黑客無法竊聽或者篡改內容了。使用TLS的時候有以下注意點:
- 盡可能使用高版本的TLS。
- 驗證X509證書鏈防止中間人攻擊。
- 盡量使用有CA發布的證書。
當然,TLS會增加連接時開銷,對低運算能力的設備而言是額外的負擔,不過如果設備是長連接的話就會避免反復連接的開銷。
Mosquitto原生支持了TLS加密,生成證書后再配置一下MQTT代理即可。
首先我們需要生成證書權威(Certificate Authority,CA)的認證和密鑰,生成過程中Common Name一定要填寫Fully Qualified Domain Name(測試起見用IP地址也湊合):
openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt
接下來生成MQTT代理使用的密鑰:
openssl genrsa -des3 -out server.key 2048
並去除密碼:
openssl genrsa -out server.key 2048
然后為MQTT代理准備一個認證注冊請求(Certificate Signing Request,CSR),這里的Common Name也要寫對:
openssl req -out server.csr -key server.key -new
最后通過CA簽署這個CSR生成MQTT代理證書:
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365
現在配置/etc/mosquitto/mosquitto.conf,確保8883端口的設置如下:
listener 8883 cafile /etc/mosquitto/tls/ca.crt certfile /etc/mosquitto/tls/server.crt keyfile /etc/mosquitto/tls/server.key
重啟Mosquitto服務就可以用以下命令訂閱和發布消息了,當然所有消息都由TLS加密,可以無憂無慮地傳遞私密信息啦:
mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crt mosquitto_pub -h host -p 8883 -t 'topic' -m '15' --cafile ca.crt
其中,host需要與前面指定的Common Name一致,否則TLS連接會報錯,錯誤信息也不是很直觀……
認證
認證是驗證設備身份的過程。拿旅行做比方,在換登機牌的時候需要出示護照以驗明正身,即使別人能夠假冒你的名字,但是拿不出護照便無法偽造身份。買房的時候,需要通過戶口本證明你媽是你媽。
MQTT支持兩種層次的認證:
- 傳輸層:傳輸層使用TLS不但可以加密通訊,還可以使用X509證書來認證設備。
- 應用層:MQTT支持客戶標識、用戶名密碼以及X509證書,在應用層驗證設備。
通過傳輸層和應用層來解釋認證並不直觀,下面我們直接從客戶標識、用戶名密碼以及X509證書的角度來了解認證。
客戶標識
用戶可以使用最多65535個字符作為客戶標識(Client Identifier),UUID或者MAC地址最為常見。
使用客戶標識來認證並不可靠,不過在某些封閉的環境中或許已經足夠。
用戶名密碼
MQTT協議支持通過CONNECT消息的username和password字段發送用戶名和密碼。
用戶名密碼的認證使用起來非常方便,不過再強調一下,由於用戶名密碼是以明文形式傳輸,在通過互聯網時使用TSL加密是必須的。
Mosquitto支持用戶名/密碼認證方式,只要確保/etc/mosquitto/mosquitto.conf有如下設置:
password_file /etc/mosquitto/passwd allow_anonymous false
其中passwd文件是用來保存用戶名和密碼的,可以通過mosquitto_passwd來維護用戶名密碼。之后便可以通過如下命令訂閱和發布消息了:
mosquitto_sub -h host -p 8883 -t 'topic' --cafile ca.crt -u user -P pwd mosquitto_pub -h host -p 8883 -t 'topic' -m '9' --cafile ca.crt -u user -P pwd
這里端口使用8883是假設已經配置了TLS加密的。
結合TLS加密的用戶名密碼認證,已經是相對完善的安全體系了。
X509證書
MQTT代理在TLS握手成功之后可以繼續發送客戶端的X509證書來認證設備,如果設備不合法便可以中斷連接。
使用X509認證的好處,是在傳輸層就可以驗證設備的合法性,在發送MQTT CONNECT之前便可以阻隔非法設備的連接,以節省后續不必要的資源浪費。
如果你可以控制設備的創建和設置,X509證書認證或許是個非常好的選擇。不過代價也是有的:
- 需要設計證書創建流程。如果你對設備有着完全的控制,在設備出廠前就能燒錄X509證書到設備中,那么這條路是非常合適的。但是,對於移動設備等無法實現燒錄證書的場景,用戶名/密碼認證或許是更好的選擇。
- 需要管理證書的生命周期,最好通過PKI(Public-Key-Infrastructure)來管理。
- 如果證書泄露了,一定要立即使證書失效。一個選擇是使用證書黑名單(Certificate Revocation Lists),另一個選擇是提供在線證書狀態協議(Online Certificate Status Protocol),方便MQTT代理及時了解證書的狀態。
MQTT原生支持X509認證,生成客戶證書后再配置一下MQTT代理便可。
首先生成設備密鑰:
openssl genrsa -des3 -out client.key 2048
然后為准備一個設備認證注冊請求:
openssl req -out client.csr -key client.key -new
最后通過CA簽署這個CSR生成設備證書:
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365
現在配置/etc/mosquitto/mosquitto.conf,確保8883端口的設置如下:
listener 8883
cafile
/etc/mosquitto/tls/ca
.crt
certfile
/etc/mosquitto/tls/server
.crt
keyfile
/etc/mosquitto/tls/server
.key
require_certificate
true
重啟Mosquitto服務就可以用以下命令訂閱和發布消息了,當然所有消息都由TLS加密,可以無憂無慮地傳遞私密信息啦:
mosquitto_sub -h host -p 8883 -t
'topic'
--cafile ca.crt --cert client.crt --key client.key
mosquitto_pub -h host -p 8883 -t
'topic'
-m
'95'
--cafile ca.crt --cert client.crt --key client.key
可以看到,X509同時提供了完善的加密和驗證,只是證書的生命周期管理的代價要比用戶名密碼高一些。
授權
授權是對資源的訪問權限。繼續拿機場做例子,在使用護照認證了用戶之后,系統會根據預定決定用戶可以上特定時間和班次的飛機,這就是授權。
對MQTT而言意味着對主題的訂閱和發布權限。Mosquitto內置了基本的授權,那就是基於Access Control List的授權。
由於ACL是基於特定用戶的,所以需要使用用戶名密碼認證方式。然后,在/etc/mosquitto/mosquitto.conf中指定ACL文件:
acl_file
/etc/mosquitto/acl
在這個ACL文件便可以指定用戶的讀寫權限,比如下面便可以授權用戶tom讀寫指定主題的權限:
user tom
topic readwrite company
/building/floor/
#
Mosquitto只提供了基本的基於ACL的授權,更高級的基於RBAC的授權可能需要通過插件的形式自行開發了。
體系
在MQTT項目實施時,還可以考慮通過防火牆保護MQTT代理:
- 僅允許相關的流量傳遞到MQTT代理,比如UDP、ICMP等流量可以直接屏蔽掉。
- 僅允許相關端口的流量傳遞到MQTT代理,比如MQTT over TCP使用1883,而MQTT over TLS使用8883。
- 僅允許某些IP地址段來訪問MQTT代理,如果業務場景允許的話。
篇幅有限,本文只涉及了MQTT安全體系設計的冰山一角,如果讀者感興趣還可以參考HiveMQ發布的Introducing the MQTT Security Fundamentals系列博文。堡壘往往最容易從內部攻破,只有在系統在設計的時候就把安全放在首要位置並且積極地去做威脅模型分析,這才能有效保護用戶數據。
前幾篇文章我們介紹了MQTT協議本身,雖然非常適合物聯網項目,但是在項目實施的時候有諸多不便:mosquitto等開源產品可擴展性不佳、需要自己簽發X509證書、認證與授權不靈活、MQTT服務需要自己運維等。所以,在實施物聯網服務的時候,應該采用雲端的托管服務,以便聚焦物聯網業務,而不是為了基礎架構和運維煩惱。
這次我們將通過百度開放雲物聯網服務IoT來體驗一下雲端的MQTT托管服務是一個什么樣的體驗。
背景
百度開放雲物聯網(IoT)服務是一個全托管的雲服務,幫助建立設備與雲端之間安全可靠的雙向連接,以支撐各種類型的物聯網項目,而無需考慮服務的運維。
使用物聯網服務提供如下好處:
- 從設備到雲端以及從雲端到設備可靠地進行大規模消息傳輸。
- 對設備認證與權限管理,並保證數據安全傳輸。
- 支持多種語言開發,兼容主流硬件設備。
- 與大數據服務無縫對接,以數據分析驅動業務進步。
為了更好地支持設備與雲端之間的互聯互通,百度開放雲物聯網服務原生支持MQTT(Message Queuing Telemetry Transport)協議。MQTT是基於二進制消息的發布/訂閱編程模式的消息協議,最早由IBM提出的,如今已經成為OASIS規范。與HTTP、CoAP、XMPP等協議相比,MQTT協議有以下的優勢:
- MQTT基於TCP,在反控設備的時候比CoAP等基於UDP的協議更可靠,比如使用3G通訊的時候需要專門實現CoAP over TCP,否則反控很不穩定。
- MQTT異步Pub/Sub實現,好比發個短信,無需等待對方確認便可以繼續,而不像HTTP、CoAP那樣必須等待對方應答才能返回的同步模式。
- MQTT為物聯網提供了許多體貼的設計,比如QoS,比如“遺言”等設計。
- MQTT是二進制格式,比XMPP更輕量級。
總之,通過支持輕量級可擴展的MQTT,百度開放雲物聯網服務非常適合需要低功耗和網絡帶寬有限的物聯網場景,國外的公有雲供應商如AWS、Azure、Bluemix等都以各種形式加入了對MQTT的支持。
使用物聯網服務的參考架構如下:
為了保障安全,開放雲物聯網服務的MQTT通訊都是通過SSL加密的,確保消息不會被監聽與篡改。
要使用百度物聯網服務,請到這里申請測試。目前提供的是基於命令行的用戶體驗,可以參考入門指南配置Python環境並下載命令行工具。
運維體驗
百度物聯網服務分為運維人員體驗和開發人員體驗兩部分。首先讓我們來看運維人員體驗。
首先需要創建IoT實例,以容納多個設備、身份、策略等資源:
1
|
bce.py iot create-endpoint --endpoint-name
"smart-project"
|
在實例下面可以創建一或多個設備:
1
|
bce.py iot create-thing --endpoint-name
"smart-project"
--thing-name
"sensor-100"
|
成功創建設備后,系統返回username,是用來作為標識符與MQTT服務交互的。
下面進行權限管理,保證設備能夠對特定的主題訂閱發布消息。
首先需要創建一個或多個身份(Principal)來代表物聯網服務中的認證主體。對於物聯網服務,權限綁定在身份而不是設備上的,這樣用戶可以為每個設備創建不同的身份,或者設備共享一個身份,非常靈活:
1
|
bce.py iot create-principal --endpoint-name
"smart-project"
--principal-name
"sensor-principle"
|
身份創建成功后,服務返回password。這里需要說明一下,這邊的password其實是個密鑰,只要能提供這個密鑰,系統便會賦予相應的身份。換句話說,上面創建的sensor-100可以提供這個密鑰以獲得sensor-principle身份,sensor-200如果能夠提供同樣的密鑰,系統也會把它辨識成同樣的身份,擁有身份上面所對應的一切權限。
用以下命令把這個身份綁定在設備上:
1
|
bce.py iot attach-thing-principal --endpoint-name
"smart-project"
--thing-name
"sensor-100"
--principal-name
"sensor-principle"
|
下面創建策略(Policy),以控制對消息主題的訂閱發布等操作權限。比如,用於訂閱和發布某公司B樓第5層的溫度的主題,實現方式如下:
1
|
bce.py iot create-policy --endpoint-name
"smart-project"
--policy-name
"b-5-temperature-policy"
--topic=
"building-b/floor-5/temperature"
--operation=PUBLISH --operation=SUBSCRIBE
|
創建策略成功后,便可以綁定到身份上,擁有這個身份的設備sensor-100便繼承了對主題的訂閱發布權限:
1
|
bce.py iot attach-principal-policy --endpoint-name
"smart-project"
--policy-name
"b-5-temperature-policy"
--principal-name
"sensor-principle"
|
運維人員體驗至此結束,物聯網服務已經包含了一個設置好了訪問權限的設備。
開發體驗
下面我們看一下開發人員體驗。
本質上開發人員只需要按照MQTT協議編程即可,具體的規范請參考http://mqtt.org/。實際上,由於MQTT是物聯網的標准協議,有着豐富的客戶端支持,比如Eclipse基金會提供的Paho支持Windows/Unix/Mac/Android/RTOS上C/C++/Java/Python/JavaScript/.Net語言的開發。
這里我們就以NetBeans開發環境編寫Java應用為例。新建一個Java應用程序類型的Maven項目,右擊“依賴關系”選擇添加依賴關系,查詢org.eclipse.paho,並加入對org.eclipse.paho.client.mqttv3的依賴,並在main函數中加入以下代碼:
String endpoint = "smart-project"; String username = "smart-project/sensor-100"; String password = "Dm3yyvOHb7zt/uRWadfasdfMc+uDbf4j960="; String topic = "building-b/floor-5/temperature"; // 創建SSL連接 TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); tmf.init((KeyStore)null); TrustManager[] trustManagers = tmf.getTrustManagers(); SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(null, trustManagers, null); // 配置MQTT連接 MqttConnectOptions options = new MqttConnectOptions(); options.setCleanSession(true); options.setUserName(username); options.setPassword(password.toCharArray()); options.setSocketFactory(ctx.getSocketFactory()); // 創建MQTT連接 MqttClient client = new MqttClient(endpoint, "java-client"); client.connect(options); // 發送消息 MqttMessage message = new MqttMessage(); message.setPayload("15".getBytes()); client.publish(topic, message); client.disconnect();
把以上代碼植入智能設備,便可以輕松安全地向雲端發送消息了。從雲端向智能設備發送控制命令也很直觀,這里就不再贅述了。
可以看見,采用雲端的托管物聯網服務,把基礎架構與運維交給雲服務供應商,使得物聯網項目實施高效便捷了許多。百度開放雲物聯網服務為物聯網而生,不但提供了全托管的MQTT服務,在安全性與可擴展性方面也做下足了功夫,誠意十足。
IOT---MQTT 優缺點
物聯網並不僅僅是一種網絡,而是一個新的生態環境,它描述的本質是越來越多的使用物品通過網絡連接在一起並可使用單個或者多個的終端設備對它們進行各種控制和使用—當然,工業上的物聯網通常連接到的石鼓傳感器或者其他數據采集儀器以及行為單位。思科曾經預測過,物聯網市場的規模可能在14萬億美金左右,前景極為光明。眾所周知,物聯網是在傳統互聯網基礎上延伸和擴展而出的概念,用戶端從傳統的計算機延伸和擴展到了任何物品與物品之間,而物品則通過各種傳感器進行信息采集,然后通過計算設備進行網絡信息交換與通信。但是當前移動互聯網正處於起步階段,很多時候無法提供可靠的網絡保障,因此,IBM主導並提出了MQTT協議,致力於解決這一方面的問題。
什么是MQTT協議?

低協議開銷
MQTT 的獨特之處在於,它的每消息標題可以短至 2 個字節。MQ 和 HTTP 都擁有高得多的每消息開銷。對於 HTTP,為每個新請求消息重新建立 HTTP 連接會導致重大的開銷。MQ 和 MQTT 所使用的永久連接顯著減少了這一開銷。
對不穩定網絡的容忍
MQTT 和 MQ 能夠從斷開等故障中恢復,而且沒有進一步的代碼需求。但是,HTTP 無法原生地實現此目的,需要客戶端重試編碼,這可能增加冪等性問題。MQTT 是專門針對低功耗目標而設計的。HTTP 的設計沒有考慮此因素,因此增加了功耗。
在 HTTP 堆棧上,維護數百萬個並發連接,需要做許多的工作來提供支持。盡管可以實現此支持,但大多數商業產品都為處理這一數量級的永久連接而進行了優化。IBM 提供了 IBM MessageSight,這是一個單機架裝載服務器,經過測試能處理多達 100 萬個通過 MQTT 並發連接的設備。相反,MQ 不是為大量並發客戶端而設計的。
您需要能夠及時地將通知傳遞給客戶。為此,必須采用某種定期輪詢或推送方法;從電池、系統負載和帶寬角度講,推送是最佳解決方案。
HTTP 和 MQTT 客戶端都已在大量平台上實現。MQTT 的簡單性有助於以極少的精力在額外的客戶端上實現 MQTT。
一些企業防火牆將出站連接限制到一些已定義的端口。這些端口通常被限制為 HTTP(80 端口)、HTTPS(443 端口)等。HTTP 顯然可以在這些情況下運行。MQTT 可 封裝在一個 WebSockets 連接中,顯示為一個 HTTP 升級請求,從而允許在這些情況下運行。MQ 不允許采用這種模式。
——不支持與第三方HTTP的集成,雖然MQTT協議優於普通的HTTP協議,但是基於傳統的HTTP協議的WEB服務器仍然占主流市場,那么這些服務器要實現與MQTT協議的互聯互通,以降低升級成本也尤為關鍵。
——不支持負載均衡,為防止高並發和惡意攻擊,負載均衡服務器也必不可少。
——不支持用戶管理接口,用戶在進行設備的行為數據分析的時候,顯得尤為重要,這又是工業4.0、大數據時代的必然需求。
——不支持離線消息,彌補設備離線以后,MQTT服務器對設備的控制信息丟失的問題。
——不支持點對點通信,采用標准的MQTT協議,理論上可以通過相互訂閱的方式實現點對點通信,但是邏輯相對復雜,並且對設備的安全性方面存在擔憂。當設備B和設備C在同一主題的情況下,設備A無法知道是設備B還是設備C發送的消息,也有可能消息被設備D竊聽。
小e1Wi-Fi全功能開發板采用ESP8266 WiFi SOC 芯片,采用Free RTOS實時操作系統,主頻可達160MHZ。支持標准的 IEEE802.11 b/g/n 協議,完整的 TCP/IP 協議棧,具有豐富的硬件接口,並配備OLED屏,溫濕度傳感器,大氣壓傳感器,RGB,IR等,利用微信進行遠程控制與語音互動,代碼開源。
小e2 2G透明串口開發板,是利用SIM卡和運營商的GPRS網絡提供無線數據傳輸功能的開發板,通過此開發板的2G模塊,可以提供各種設備(PC、手機、服務器)到模塊間的透明的數據交互
參考地址:
管理控制台: https://www.jianshu.com/p/ae76ac570f51
IOT(9)---MQTT 優缺點:https://blog.csdn.net/zhangbijun1230/article/details/79755138