一、mqtt介紹
??MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸協(xié)議),是一個基于客戶端-服務(wù)器的消息發(fā)布/訂閱傳輸協(xié)議。MQTT協(xié)議是輕量、簡單、開放和易于實現(xiàn)的,這些特點使它適用范圍非常廣泛。在很多情況下,包括受限的環(huán)境中,如:機器與機器(M2M)通信和物聯(lián)網(wǎng)(IoT)。其在,通過衛(wèi)星鏈路通信傳感器、偶爾撥號的醫(yī)療設(shè)備、智能家居、及一些小型化設(shè)備中已廣泛使用。
??MQTT有三種角色的存在:
??????Broker代理:很多人理解為中間件,當然可以這樣子認為。他就是一個中間件。用于處理信息并發(fā)送到相應的訂閱者。
??????發(fā)布者:用于發(fā)布信息到代理上面。注意:發(fā)布者也可以是訂閱者。
??????訂閱者:就是用于接受信息的客戶端。
??MQTT使用TCP/IP提供網(wǎng)絡(luò)連接,主流的MQTT是基于TCP連接進行數(shù)據(jù)推送的,但是同樣有基于UDP的版本,叫做MQTT-SN
??三種消息發(fā)布服務(wù)質(zhì)量:
????“至多一次”,消息發(fā)布完全依賴底層TCP/IP網(wǎng)絡(luò)。會發(fā)生消息丟失或重復。這一級別可用于如下情況,環(huán)境傳感器數(shù)據(jù),丟失一次讀記錄無所謂,因為不久后還會有第二次發(fā)送。這一種方式主要普通APP的推送,倘若你的智能設(shè)備在消息推送時未聯(lián)網(wǎng),推送過去沒收到,再次聯(lián)網(wǎng)也就收不到了。
????“至少一次”,確保消息到達,但消息重復可能會發(fā)生。
????“只有一次”,確保消息到達一次。在一些要求比較嚴格的計費系統(tǒng)中,可以使用此級別。在計費系統(tǒng)中,消息重復或丟失會導致不正確的結(jié)果。這種最高質(zhì)量的消息發(fā)布服務(wù)還可以用于即時通訊類的APP的推送,確保用戶收到且只會收到一次
??MQTT協(xié)議中的方法:
????Connect:等待與服務(wù)器建立連接
????Disconnect:等待MQTT客戶端完成所作的工作,并于服務(wù)器斷開TCP/IP會話
????Subscribe:等待完成訂閱
????UnSubscribe:等待服務(wù)器取消客戶端的一個活多個和topics訂閱
????Publish:MQTT客戶端發(fā)送消息請求,發(fā)送完成后返回應用程序線程
??優(yōu)點:
????低開銷、低帶寬占用,可以以極少的代碼和有限的帶寬,為連接遠程設(shè)備提供實時可靠的消息服務(wù)。
二、在windows上安裝mqtt服務(wù)器:
1.mosquitto介紹
??Mosquitto是一款實現(xiàn)了消息推送協(xié)議MQTT 3.1的開源消息代理軟件,提供輕量級的、支持可訂閱/可發(fā)布的消息推送模式,是設(shè)備與設(shè)備之間的短消息通信變得簡單,廣泛應用于低功耗傳感器、手機(app消息推送是場景之一)、嵌入式電腦、微型控制器等移動設(shè)備。
2.下載mosquitto
下載地址:https://mosquitto.org/download/
3.安裝mosquitto
4.配置文件修改
4.1 mosquitto.conf文件修改
4.2 以管理員身份打開Windows PowerShell, 進行用戶密碼配置
4.3 重啟mosquitto broker服務(wù)
4.4 測試服務(wù)器
三、編譯qtmqtt和創(chuàng)建mqtt客戶端工程
Qt在5.10版本開始支持mqtt,但是也沒有集成到安裝包里面,需要自己下載編譯
1.先下載安裝Perl (解決編譯qtmqtt報perl錯誤)
下載地址:https://www.perl.org/get.html
ActivePerl_x64_5.24.1.2402.exe
2.下載安裝qtmqtt
下載地址:https://github.com/emqx/qmqtt
打開工程文件,選擇src執(zhí)行qmake,然后點擊構(gòu)建即可生成相應的庫文件
3.創(chuàng)建myMqttDemo客戶端工程
我的demo工程下載地址:https://download.csdn.net/download/linyibin_123/87280629
4.拷貝鏈接庫與頭文件到demo工程指定位置
4.1 拷貝頭文件:
4.2 拷貝庫文件:
4.3 demo工程引用庫文件:
四、mqtt客戶端demo工程代碼
mqttClient.h
#ifndef MQTTCLIENT_H
#define MQTTCLIENT_H
#include <QObject>
#include "qmqtt.h"
class mqttClient : public QObject
{
Q_OBJECT
public:
mqttClient();
static mqttClient& getInstance();
void init(QString sIp, quint16 nPort, QString sClientId, QString sUser, QString sPwd);
private:
QMQTT::Client *m_pClient;
signals:
void sig_result_connect();
void sig_result_disconnect();
void sig_result_dataReceived(QMQTT::Message message);
public slots:
void slot_connect();
void slot_disconnect();
void slot_publish(QString sTopic, QString sPayload);
void slot_subscribe(QString sTopic);
void slot_unSubscribe(QString sTopic);
void on_dataReceived(QMQTT::Message message);
};
#endif // MQTTCLIENT_H
mqttClient.cpp
#include "mqttclient.h"
mqttClient::mqttClient()
{
m_pClient = nullptr;
}
mqttClient &mqttClient::getInstance()
{
static mqttClient s_obj;
return s_obj;
}
void mqttClient::init(QString sIp, quint16 nPort, QString sClientId, QString sUser, QString sPwd)
{
if(m_pClient)
{
delete m_pClient;
m_pClient = nullptr;
}
m_pClient = new QMQTT::Client(QHostAddress(sIp), nPort);
if(m_pClient)
{
qDebug() << "m_pClient Create Success.";
m_pClient->setClientId(sClientId);
m_pClient->setUsername(sUser);
m_pClient->setPassword(sPwd.toLatin1());
m_pClient->setKeepAlive(60);
connect(m_pClient, &QMQTT::Client::connected, this, &mqttClient::sig_result_connect);
connect(m_pClient, &QMQTT::Client::disconnected, this, &mqttClient::sig_result_disconnect);
connect(m_pClient, SIGNAL(received(QMQTT::Message)), this, SLOT(on_dataReceived(QMQTT::Message)));
}
}
void mqttClient::slot_connect()
{
qDebug() << "connect 000";
if(m_pClient)
{
if(!m_pClient->isConnectedToHost())
{
qDebug() << "connect 111";
m_pClient->connectToHost();
}
}
}
void mqttClient::slot_disconnect()
{
qDebug() << "disconnect";
if(m_pClient->isConnectedToHost())
{
m_pClient->disconnectFromHost();
}
}
void mqttClient::slot_publish(QString sTopic, QString sPayload)
{
if(sTopic.isEmpty() || sPayload.isEmpty())
{
qDebug() << "sTopic or sPayload is empty";
return;
}
QMQTT::Message message(136, sTopic, sPayload.toUtf8());
m_pClient->publish(message);
}
void mqttClient::slot_subscribe(QString sTopic)
{
if(sTopic.isEmpty())
{
qDebug() << "sTopic is empty";
return;
}
m_pClient->subscribe(sTopic);
}
void mqttClient::slot_unSubscribe(QString sTopic)
{
if(sTopic.isEmpty())
{
qDebug() << "sTopic is empty";
return;
}
m_pClient->unsubscribe(sTopic);
}
void mqttClient::on_dataReceived(QMQTT::Message message)
{
qDebug() << "on_dataReceived";
emit sig_result_dataReceived(message);
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "mqttclient.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void sig_btn_connect();
void sig_btn_disconnect();
void sig_btn_publish(QString sTopic, QString sPayload);
void sig_btn_subscribe(QString sTopic);
void sig_btn_unSubscribe(QString sTopic);
private slots:
void on_pushButton_Connect_clicked();
void on_pushButton_Publish_clicked();
void on_pushButton_Subscribe_clicked();
void on_pushButton_UnScribe_clicked();
void slot_result_connect();
void slot_result_disconnect();
void slot_result_dataReceived(QMQTT::Message message);
void on_pushButton_DisConnect_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(this, SIGNAL(sig_btn_connect()),
&mqttClient::getInstance(), SLOT(slot_connect()));
connect(this, SIGNAL(sig_btn_disconnect()),
&mqttClient::getInstance(), SLOT(slot_disconnect()));
connect(this, SIGNAL(sig_btn_publish(QString, QString)),
&mqttClient::getInstance(), SLOT(slot_publish(QString, QString)));
connect(this, SIGNAL(sig_btn_subscribe(QString)),
&mqttClient::getInstance(), SLOT(slot_subscribe(QString)));
connect(this, SIGNAL(sig_btn_unSubscribe(QString)),
&mqttClient::getInstance(), SLOT(slot_unSubscribe(QString)));
connect(&mqttClient::getInstance(), SIGNAL(sig_result_connect()),
this, SLOT(slot_result_connect()));
connect(&mqttClient::getInstance(), SIGNAL(sig_result_disconnect()),
this, SLOT(slot_result_disconnect()));
connect(&mqttClient::getInstance(), SIGNAL(sig_result_dataReceived(QMQTT::Message)),
this, SLOT(slot_result_dataReceived(QMQTT::Message)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_Connect_clicked()
{
QString sIp = ui->lineEdit_IP->text().trimmed();
quint16 nPort = (quint16)ui->lineEdit_Port->text().toInt();
QString sClientId = ui->lineEdit_ClientId->text().trimmed();
QString sUser = ui->lineEdit_User->text().trimmed();
QString sPwd = ui->lineEdit_Password->text().trimmed();
mqttClient::getInstance().init(sIp, nPort, sClientId, sUser, sPwd);
emit sig_btn_connect();
}
void MainWindow::on_pushButton_Publish_clicked()
{
QString sTopic = ui->lineEdit_Topic->text().trimmed();
QString sPayload = ui->lineEdit_Message->text().trimmed();
emit sig_btn_publish(sTopic, sPayload);
}
void MainWindow::on_pushButton_Subscribe_clicked()
{
QString sTopic = ui->lineEdit_Topic_2->text().trimmed();
emit sig_btn_subscribe(sTopic);
}
void MainWindow::on_pushButton_UnScribe_clicked()
{
QString sTopic = ui->lineEdit_Topic_2->text().trimmed();
emit sig_btn_unSubscribe(sTopic);
}
void MainWindow::slot_result_connect()
{
qDebug() << "result:Connected";
ui->label_Status->setText("Connected");
}
void MainWindow::slot_result_disconnect()
{
qDebug() << "result:Unconnected";
ui->label_Status->setText("Unconnected");
}
void MainWindow::slot_result_dataReceived(QMQTT::Message message)
{
QString sMes = QString(message.id()) + " " + QString(message.qos()) + QString(message.topic()) + message.payload() + "\n";
ui->textEdit_Log->append(sMes);
}
void MainWindow::on_pushButton_DisConnect_clicked()
{
emit sig_btn_disconnect();
}
五、客戶端與服務(wù)器連接調(diào)試結(jié)果
開啟Windows PowerShell,執(zhí)行服務(wù)和訂閱發(fā)布操作,開啟程序連接服務(wù)器,并執(zhí)行訂閱和發(fā)布操作,雙方都可以收到對方發(fā)布的消息。文章來源:http://www.zghlxwxcb.cn/news/detail-741027.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-741027.html
到了這里,關(guān)于mqtt服務(wù)器搭建與qt下的mqtt客戶端實現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!