1、MQTT是什么
MQTT(Message Queuing Telemetry Transport)是一種輕量級(jí)的消息協(xié)議,設(shè)計(jì)用于在低帶寬、不穩(wěn)定或高延遲的網(wǎng)絡(luò)環(huán)境中傳輸消息。MQTT最初由IBM開(kāi)發(fā),后來(lái)成為OASIS標(biāo)準(zhǔn),廣泛用于物聯(lián)網(wǎng)(IoT)應(yīng)用和其他需要高效消息傳遞的場(chǎng)景。
MQTT是輕量級(jí)基于代理的發(fā)布/訂閱的消息傳輸協(xié)議,它可以通過(guò)很少的代碼和帶寬和遠(yuǎn)程設(shè)備連接。例如通過(guò)衛(wèi)星和代理連接,通過(guò)撥號(hào)和醫(yī)療保健提供者連接,以及在一些自動(dòng)化或小型設(shè)備上,而且由于小巧,省電,協(xié)議開(kāi)銷小和能高效的向一和多個(gè)接收者傳遞信息,故同樣適用于移動(dòng)應(yīng)用設(shè)備上。
- 早在1999年,IBM的Andy Stanford-Clark博士以及Arcom公司ArlenNipper博士發(fā)明了MQTT(Message Queuing Telemetry Transport,消息隊(duì)列遙測(cè)傳輸)技術(shù) 。
- MQTT的話題是他們?cè)谡務(wù)撻_(kāi)源物聯(lián)網(wǎng)平臺(tái)Pachube時(shí)提到的。Stanford-Clark認(rèn)為Pachube很酷,其不足之處是不具備真正的推送功能。你需要不斷的進(jìn)行輪詢才能得到即時(shí)數(shù)據(jù)。這正是MQTT能夠?qū)崿F(xiàn)的,他提到了使用推送通信系統(tǒng)的石油管道檢測(cè)系統(tǒng)。
2、MQTT協(xié)議的關(guān)鍵概念和特性
以下是MQTT協(xié)議的一些關(guān)鍵概念和特性:
1. 發(fā)布/訂閱模型:
MQTT采用發(fā)布/訂閱模型,消息的發(fā)送者稱為發(fā)布者(Publisher),而消息的接收者稱為訂閱者(Subscriber)。發(fā)布者將消息發(fā)布到主題(Topic),而訂閱者可以選擇訂閱特定主題以接收相關(guān)消息。
2. 主題(Topic):
主題是MQTT中消息的分類標(biāo)識(shí),用于將消息發(fā)送到特定的目標(biāo)。訂閱者可以通過(guò)訂閱特定主題來(lái)接收與該主題相關(guān)的消息。主題可以是層次結(jié)構(gòu)的,例如:home/living-room/temperature
,其中home
是根主題,living-room
是home
的子主題,temperature
是living-room
的子主題。
3. 消息質(zhì)量等級(jí)(QoS):
MQTT支持不同的消息質(zhì)量等級(jí),用于確保消息傳遞的可靠性。共有三個(gè)等級(jí):
- QoS 0: 最多一次傳遞,消息可能會(huì)丟失或重復(fù)。
- QoS 1: 至少一次傳遞,確保消息至少被接收一次。
- QoS 2: 剛好一次傳遞,確保消息僅被接收一次。
4. 保留消息:
發(fā)布者可以發(fā)送保留消息,這是一個(gè)持久的消息,當(dāng)有新訂閱者訂閱與保留消息相匹配的主題時(shí),將立即發(fā)送該消息。這對(duì)于傳遞重要信息或者初始化狀態(tài)很有用。
5. 遺囑消息(Will Message):
連接到MQTT代理的客戶端可以指定一個(gè)遺囑消息。如果客戶端非正常斷開(kāi)連接,代理將自動(dòng)發(fā)布遺囑消息到預(yù)定的主題。這可用于通知其他客戶端某個(gè)設(shè)備的狀態(tài)變化。
6. 保持活動(dòng)性(Keep Alive):
MQTT使用保持活動(dòng)性機(jī)制來(lái)確??蛻舳伺c代理之間的連接保持活動(dòng)??蛻舳藭?huì)定期向代理發(fā)送保持活動(dòng)性的消息,如果代理在指定的時(shí)間內(nèi)未收到客戶端的消息,將關(guān)閉連接。
7. 連接過(guò)程:
MQTT的連接過(guò)程包括客戶端向代理發(fā)送連接請(qǐng)求、代理響應(yīng)并確認(rèn)連接、客戶端發(fā)送連接信息、代理確認(rèn)連接信息。在這個(gè)過(guò)程中,客戶端和代理之間會(huì)協(xié)商使用的MQTT版本、連接的用戶名和密碼、保持活動(dòng)性時(shí)間等。
8. 安全性:
MQTT本身并沒(méi)有內(nèi)建的安全性機(jī)制,但可以通過(guò)TLS/SSL進(jìn)行加密傳輸。此外,可以通過(guò)用戶名和密碼進(jìn)行身份驗(yàn)證,以及通過(guò)訪問(wèn)控制列表(ACL)限制客戶端的訪問(wèn)權(quán)限。
3、MQTT客戶端代碼示例
實(shí)現(xiàn)一個(gè)完整的MQTT協(xié)議是一個(gè)龐大而復(fù)雜的任務(wù),因?yàn)镸QTT涉及到多個(gè)方面,包括連接、發(fā)布/訂閱、消息質(zhì)量等級(jí)等。下面是一個(gè)簡(jiǎn)化的C++實(shí)現(xiàn)的示例,用于建立一個(gè)基本的MQTT客戶端,演示連接到MQTT代理服務(wù)去發(fā)布/訂閱消息。
該示例使用了 Eclipse Paho MQTT C++ 客戶端庫(kù),該庫(kù)提供了MQTT協(xié)議的C++實(shí)現(xiàn)。有興趣的小獲取可以去官網(wǎng)了解一下。
首先,確保你已經(jīng)安裝了 Paho MQTT C++ 客戶端庫(kù)。可以從Paho官網(wǎng)獲取該庫(kù)。
接下來(lái),以下是一個(gè)簡(jiǎn)單的C++示例:
#include <iostream>
#include <mqtt/async_client.h>
class MQTTCallbacks : public virtual mqtt::callback, public virtual mqtt::iaction_listener {
void connectionLost(const std::string& cause) override {
std::cout << "Connection lost: " << cause << std::endl;
}
void deliveryComplete(mqtt::delivery_token_ptr tok) override {
std::cout << "Message delivered" << std::endl;
}
void onSuccess(const mqtt::token& tok) override {
std::cout << "Action successful" << std::endl;
}
void onFailure(const mqtt::token& tok) override {
std::cout << "Action failed" << std::endl;
}
};
int main() {
const std::string brokerAddress = "tcp://localhost:1883";
const std::string clientId = "cpp_mqtt_client";
const std::string topic = "test/topic";
mqtt::async_client client(brokerAddress, clientId);
MQTTCallbacks callbacks;
client.set_callback(callbacks);
mqtt::connect_options connOpts;
connOpts.set_keep_alive_interval(20);
connOpts.set_clean_session(true);
try {
std::cout << "Connecting to the broker..." << std::endl;
client.connect(connOpts)->wait();
std::cout << "Connected!" << std::endl;
std::string payload = "Hello, MQTT!";
mqtt::message_ptr pubmsg = mqtt::make_message(topic, payload);
pubmsg->set_qos(1);
client.publish(pubmsg)->wait();
std::cout << "Message published" << std::endl;
client.subscribe(topic, 1)->wait();
while (true) {
// Continue to keep the program running
std::this_thread::sleep_for(std::chrono::seconds(1));
}
client.unsubscribe(topic)->wait();
client.disconnect()->wait();
} catch (const mqtt::exception& exc) {
std::cerr << "Error: " << exc.what() << std::endl;
return 1;
}
return 0;
}
該示例假定了本地運(yùn)行的MQTT代理地址為 tcp://localhost:1883
,客戶端連接后發(fā)布了一條消息到主題 test/topic
,并訂閱了該主題。實(shí)際開(kāi)發(fā)中我們需要修改 brokerAddress
和其他參數(shù)。
需要說(shuō)明的是這只是一個(gè)簡(jiǎn)單的示例,實(shí)際上MQTT的實(shí)現(xiàn)要更加復(fù)雜,需要處理連接丟失、重連、消息質(zhì)量等級(jí)等情況。在實(shí)際應(yīng)用中,建議使用現(xiàn)成的MQTT客戶端庫(kù),以確保正確性和穩(wěn)定性。
小結(jié)
MQTT在實(shí)際開(kāi)發(fā)中需要學(xué)習(xí)的內(nèi)容有很多,而且很多細(xì)節(jié)需要注意。希望正在學(xué)習(xí)MQTT協(xié)議的小伙伴通過(guò)本節(jié)內(nèi)容對(duì)MQTT協(xié)議有個(gè)初步的認(rèn)識(shí)。
題外話:學(xué)習(xí)技術(shù)是一個(gè)慢慢沉淀的過(guò)程。不積跬步無(wú)以至千里,技術(shù)同樣如此。希望小伙伴們?cè)谝院蟮募夹g(shù)路上堅(jiān)持下去,并到達(dá)一片開(kāi)闊的境地。