本文首發於個人網站,永久地址:[https://iiter.cn/blogs/13](https://iiter.cn/blogs/13) 點進去給幾個訪問量也行啊
github 倉庫源代碼:[github](https://github.com/isnl/mqtt-server)
@[toc]
### MQTT 的概念
> MQTT(Message Queue Telemetry Transport,翻譯成中文為消息隊列遙測傳輸)是 ISO 標准(ISO/IEC PRF 20922)下基於發布/訂閱范式的消息協議。它工作在 TCP/IP 協議族上,是為硬件性能低下的遠程設備以及網絡狀況糟糕的情況下而設計的發布/訂閱型消息協議,為此,它需要一個消息中間件 。<br>
> MQTT 是一個基於客戶端-服務器的消息發布/訂閱傳輸協議。MQTT 協議是輕量、簡單、開放和易於實現的,這些特點使它適用范圍非常廣泛。在很多情況下,包括受限的環境中,如:機器與機器(M2M)通信和物聯網(IoT)。其在,通過衛星鏈路通信傳感器、偶爾撥號的醫療設備、智能家居、及一些小型化設備中已廣泛使用。
看到這,我們可能或許大概已經明白,MQTT 這貨就是個通信協議,且被廣泛應用在 M2M、IoT、智能家居等環境中。下面這張圖,可以讓我們更清楚的了解它具體的應用場景

### 和其他傳輸協議的區別
看到這里就有人想不明白了,MQTT 既然也是一個基於客戶端-服務器的消息發布/訂閱傳輸協議,那么它和我們平常所使用的 websocket 有什么區別呢?
借用百度物聯網產品經理的知乎回答:
兩者的應用場景不一樣:
- MQTT 是為了物聯網場景設計的基於 TCP 的 Pub/Sub 協議,有許多為物聯網優化的特性,比如適應不同網絡的 QoS、層級主題、遺言等等。
- WebSocket 是為了 HTML5 應用方便與服務器雙向通訊而設計的協議,HTTP 握手然后轉 TCP 協議,用於取代之前的 Server Push、Comet、長輪詢等老舊實現。兩者之所有有交集,是因為一個應用場景:如何通過 HTML5 應用來作為 MQTT 的客戶端,以便接受設備消息或者向設備發送信息,那么 MQTT over WebSocket 自然成了最合理的途徑了。
### MQTT 客戶端的語言支持
- Java
- Javascript
- C/C++
- Python
- Ruby
- Objective-C
### 搭建基於 nodejs 的 MQTT 服務器
#### 創建服務端
1.先從初始化一個 ==package.json== 開始。
```bash
npm init
```
2.安裝 mqtt 服務器必要依賴項 ==mosca== ==mqtt==
```bash
npm install mosca mqtt
```
3.根目錄下創建 ==mqtt.js== 文件,寫入以下內容,創建 mqtt 簡易服務器。
```javascript
const mosca = require("mosca");
const MqttServer = new mosca.Server({
port: 1883
});
MqttServer.on("clientConnected", function(client) {
//當有客戶端連接時的回調.
console.log("client connected", client.id);
});
/**
* 監聽MQTT主題消息
* 當客戶端有連接發布主題消息時
**/
MqttServer.on("published", function(packet, client) {
var topic = packet.topic;
switch (topic) {
case "temperature":
// console.log('message-publish', packet.payload.toString());
//MQTT可以轉發主題消息至其他主題
//MqttServer.publish({ topic: 'other', payload: 'sssss' });
break;
case "other":
console.log("message-123", packet.payload.toString());
break;
}
});
MqttServer.on("ready", function() {
//當服務開啟時的回調
console.log("mqtt is running...");
});
```
#### 創建客戶端推送
根目錄下創建 ==publish.js== 推送文件,寫入以下內容:
```javascript
const mqtt = require("mqtt");
const client = mqtt.connect("mqtt://127.0.0.1:1883"); //連接到mqtt服務端
//寫個定時器定時每隔3秒定時推送天氣信息,此業務可替換為自己的實際需求
setInterval(function() {
const value = Math.ceil(Math.random() * 40);
client.publish("temperature", value.toString(), { qos: 0, retain: true });
}, 3000);
```
#### 創建客戶端接收
根目錄下創建 ==subscribe.js== 接收文件,寫入以下內容:
```javascript
const mqtt = require("mqtt");
// const mqtt = require('./node_modules/mqtt/dist/mqtt.min.js')
const client = mqtt.connect("mqtt://127.0.0.1:1883"); //指定服務端地址和端口
client.on("connect", function() {
console.log("服務器連接成功");
// connected = client.connected
client.subscribe("temperature", { qos: 1 }); //訂閱主題為test的消息
});
client.on("message", function(top, message) {
console.log("當前topic:", top);
console.log("當前溫度:", message.toString());
});
```
#### 測試功能
1.啟動服務端 ==mqtt.js==
根目錄下命令行輸入 node mqtt.js/node mqtt 運行服務端,啟動成功出現以下信息:

<!-- 
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hIsGxlbH-1575468975915)(https://shop.io.mi-img.com/app/shop/img?id=shop_87298107f4129f0575fcb2cdca25ce6d.png)]


 -->
2.啟動推送客戶端 ==publish.js==
根目錄下命令行輸入 node publish.js/node publish 運行推送客戶端 3.啟動接收客戶端 ==subscribe.js==
根目錄下命令行輸入 node subscribe.js/node subscribe 運行接收客戶端,不出意外,控制台將會每隔 5 秒打印以下信息:

<!-- 
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-XXcXGAo5-1575468975922)(https://shop.io.mi-img.com/app/shop/img?id=shop_66ae3164b8f7379a3b66acec881a6cc1.gif)]


 -->
至此,一個基於 nodejs 的簡易 mqtt 服務器就搭建完成了。
