mosquitto 做爲一個消息代理, 客戶端與 mosquitto 服務端的通訊時基於 MQTT 協議的, 而如今的主流 web 應用時呈如今瀏覽器中, 這意味着用戶與服務端只能經過 HTTP 或者 HTTPS 這類瀏覽器能理解的協議傳輸, 因此後端還要創建一個代理層, 將 HTTP 協議傳輸的內容解析一下以 MQTT 協議發送到 mosquitto, 最後再由 mosquitto 發送到硬件端. javascript
在瀏覽器支持的協議中, 還有一個適用於長鏈接的 WS 協議, 參考: 瀏覽器中常見網絡協議介紹. 若是客戶端直接經過 websocket 鏈接到 mosquitto 端, 那麼就不須要中間的後端代理層. 後端只須要一個推送服務和控制系統就能夠實現對客戶端的監聽, 控制, 推送(固然, 若是業務量巨大, 業務邏輯複雜, 代理層仍是有必要的, 由於這樣不但能夠爲 mosquitto 過濾一些沒必要要的業務, 並且能夠作一些數據統計, 設計事件鉤子).html
在編譯 mosquitto 和它的驗證插件 mosquitto-auth-plug 的時候, 我注意到 mosquitto 有一個監聽的 9001 端口, 過後查了一下, 發現 mosquitto 開放的這個端口是支持直接與客戶端進行 websocket 通訊的.java
其實純粹的 MQTT 服務器是沒有這個功能的, mosquitto 須要在編譯的時候設置 configure.mk
中web
WITH_WEBSOCKETS := yes
所幸的是, eclipse 官方的 docker 鏡像 已經支持了 websocket 通訊方式. 只須要在 mosquitto.conf
中啓用:ajax
port 1883 listener 9001 protocol websockets
eclipse 提供了用於 瀏覽器客戶端利用 javascript 和 mosquitto 進行 websocket 通訊的 paho-mqtt.js, 這是這個 js 庫的文檔: Paho.MQTT DOC.docker
咱們假設有客戶端用戶爲 client
, 服務端用戶爲 server
. 爲他們分配的主題與權限爲:json
id | username | topic | rw ----+----------+--------------------+---- 1 | client | /p/client/upload | 2 2 | server | /p/client/upload | 2 3 | client | /p/client/download | 1 4 | server | /p/client/download | 2
那麼 server 和 client 都可以在 /p/client/upload
讀寫. 咱們約定只有 client 在 /p/client/upload
寫, server 只讀 /p/client/upload
, 這個 topic 是用於 client 向 server 發送消息.小程序
對於 topic /p/client/download
, server 可讀可寫, client 只讀, 這個 topic 是用於 client 接受 server 向下推送的消息, 具體的邏輯以下:後端
注意這裏的 client 是對 /p/client/upload
具備可讀可寫權限的, 意味者它能夠讀取來自 /p/client/upload
的信息, 可是實際上這裏沒有人往這個主題發佈消息(除非 client 本身往這裏發消息), 因此 client 擁有可讀權限也沒有關係.微信小程序
建議看一下這篇文章: Using MQTT Over WebSockets with Mosquitto, 它比較詳細地介紹了客戶端經過 websocket 於 mosquitto 服務器通訊的方式.
好比對於 client.html
:
先引入 paho-mqtt.js
, 這裏咱們先用 cloudflare.com CDN上的這段 js:
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.2/mqttws31.js"></script>
下面是建立客戶端 websocket 的例子:
var mqtt; var host = 'mosquitto'; var port = 9001; // onConnect 事件 function onConnect() { console.log('connected.'); var raw_message = 'Hello World!'; message = new Paho.MQTT.Message(raw_message); message.destinationName = '/p/client/upload'; console.log('sending message: ' + raw_message ); mqtt.send(message); // 訂閱 download topic var subOptions = { qos: 1, onSuccess: onSubscribe }; mqtt.subscribe('/p/client/download', subOptions); } // 訂閱主題成功事件 function onSubscribe(context) { console.log('subscribe success'); console.log(context); } // 鏈接失敗事件 function onFailure(message) { console.log('connect failed.'); } // onMessageArrived 事件 function onMessageArrived(message) { console.log('new message arrived...'); console.log(message.payloadString); } // 創建 MQTT websocket 鏈接 function MQTTconnect() { console.log('connecting to ' + host + ':' + port); mqtt = new Paho.MQTT.Client(host, port, 'clientid'); var options = { timeout: 3, onSuccess: onConnect, onFailure: onFailure, userName: 'client', password: '123456', mqttVersion: 4 }; mqtt.onMessageArrived = onMessageArrived; mqtt.connect(options); }
這裏咱們利用 paho-mqtt.js 新建了一個 mqtt
, 而後綁定 onSuccess
(鏈接成功), onFailure
(鏈接失敗) onMessageArrived
(消息到來)等事件, 以後用 options
裏的配置鏈接到遠程的 mosquitto 服務器. 鏈接成功後, client 向 server 發送一條消息到 /p/client/upload
topic, 通知服務端已經創建鏈接. 發送以後 mqtt
又訂閱 /p/client/download
, 準備接受來自服務端的信息.
好比, 服務端能夠這樣向客戶端推送消息:
import paho.mqtt.publish as publish import time HOST = 'mosquitto' PORT = 1883 if __name__ == '__main__': client_id = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) publish.single( '/p/client/download', 'hello mqtt', qos=2, hostname=HOST, port=PORT, client_id=client_id, auth={'username': 'server', 'password': '123456'})
這就是基於雙通道的服務端於客戶端通訊
單通道通訊原理相似, 可是因爲客戶端可能有多臺設備, 好比手機端, 微信小程序端, PC 端. 那麼身份的驗證不能直接由 mosquitto 肯定, 應該在消息體內肯定. 好比咱們用 json 做爲消息的承載方式. 消息體能夠這樣:
{ "timestamp": "1539141568", "client_id": "1001001", "message_type": "ping", "data": {"detail": "content"}, "token": "auth_token" }
這裏應該按照具體的業務需求進行鑑權設計.