Qt開發MQTT(一) 之Qt官方Qt MQTT


概述
Qt開發MQTT程序有兩種方式,一個是Qt官方提供的基於MQTT的封裝,一個是第三方(EMQ)開發的用於Qt調用MQTT的接口,二者使用方法大同小異,並且均提供了源碼。那么,這里先來介紹第一種,如基於Qt官方提供的封裝來使用MQTT。

Qt官方雖然在2017年就已經提供了對MQTT的封裝,但是並沒有正式加入到Qt的標准庫里面,所以需要自己下載源碼進行編譯。

Qt官方介紹文檔地址:https://doc.qt.io/QtMQTT/qtmqtt-index.html

下載
Qt官方在github上提供了源代碼,地址:https://github.com/qt/qtmqtt

這是最新的,基於MQTT 5.0協議的版本。先把源碼下載下來。

編譯
下載源碼后得到如下文件,直接打開工程文件准備編譯

我這里的編譯環境是:Qt5.12.3+vs2017

注意,編譯這個源碼需要安裝perl,否則會報錯:perl 不是內部或外部命令,也不是可運行的程序。

perl下載地址:https://www.perl.org/get.html
官網下載速度比較慢,我上傳到網盤了,可以在這里下載:

鏈接:https://pan.baidu.com/s/1p5YOo-FU-ZLJUtuZSN0Rjg 提取碼:i0dm

安裝完Perl后會自動寫入環境變量, 這時候再次編譯(Release模式)QtMqtt源碼,編譯完成后得到以下文件:


bin目錄下就是我們要的庫文件:


接下來就可以將mqtt部署到自己的Qt項目中了。

部署到Qt項目
編譯出來的Qt Mqtt庫,要使用它有兩種方式,一種是直接在項目中導入外部庫和頭文件,還有一種是將其以模塊的形式部署到Qt的安裝目錄,其中第二種的好處就是,只需要做一次操作,以后需要再用Mqtt庫就可以直接調用了,不需要每次都導入外部庫。這里兩種方法都介紹一下,首先來看第一種。

導入外部庫
新建一個Qt工程
然后將剛剛編譯的源碼生成目錄下的lib文件夾中以下四個文件拷貝:


在新建工程目錄下創建lib文件夾,將拷貝的文件粘貼進去:

然后在qtmqtt源碼目錄下(qtmqtt\src\mqtt)的所有.h頭文件拷貝,在新建工程目錄下創建include文件夾,將拷貝的文件粘貼進去:


打開新建工程的pro文件,添加:

再添加庫文件引用:

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lQt5Mqtt
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lQt5Mqttd
1
2
添加include文件的引用:

INCLUDEPATH += $$PWD/include
DEPENDPATH += $$PWD/include
1
2
ok, 這樣就可以調用Qt Mqtt的庫文件了,直接可以包含頭文件來使用了。#include "QtMqtt/QMqttClient"

為了統一演示,先介紹完第二種方法后再來看demo。

部署到Qt安裝目錄
再來看第二種方法,如何將QtMqtt的庫直接部署到Qt安裝目錄中,這樣只需要部署一次,以后在任何工程中引用都不需要再額外導入庫了,相比第一種來說更方便些。

首先,將qtmqtt源碼目錄下(qtmqtt\src\mqtt)的所有.h頭文件拷貝,Qt安裝目錄下的include文件夾中創建一個mqtt目錄,將拷貝的文件粘貼進去:

然后,將源碼編譯生成目錄下的lib中以下6個文件拷貝

並粘貼到Qt安裝目錄下的lib文件夾中去:


接下來將源碼編譯生成的兩個庫文件拷貝到Qt安裝目錄的bin中:

 

最后再拷貝模塊配置文件到Qt安裝目錄中

 

ok,配置完畢,這種方式配置在新建工程中引用只需要引入模塊就可以直接使用了

QT += mqtt
1
包含頭文件

#include <QtMqtt/QtMqtt>
1
所以推薦使用第二種方式進行配置。

接下來看看Demo。

Demo演示
為了方便演示,我們直接使用Qt Mqtt源碼中自帶的示例來編譯運行。

這個示例Qt官方有詳細介紹的,https://doc.qt.io/QtMQTT/qtmqtt-simpleclient-example.html
將該示例打開,有個地方需要改一下,打開Pro文件

將以上兩行注釋掉,要不然會有依賴,無法獨立運行。

關鍵代碼:

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtCore/QDateTime>
#include <QtMqtt/QMqttClient>
#include <QtWidgets/QMessageBox>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

m_client = new QMqttClient(this);
m_client->setHostname(ui->lineEditHost->text());
m_client->setPort(ui->spinBoxPort->value());

connect(m_client, &QMqttClient::stateChanged, this, &MainWindow::updateLogStateChange);
connect(m_client, &QMqttClient::disconnected, this, &MainWindow::brokerDisconnected);

connect(m_client, &QMqttClient::messageReceived, this, [this](const QByteArray &message, const QMqttTopicName &topic) {
const QString content = QDateTime::currentDateTime().toString()
+ QLatin1String(" Received Topic: ")
+ topic.name()
+ QLatin1String(" Message: ")
+ message
+ QLatin1Char('\n');
ui->editLog->insertPlainText(content);
});

connect(m_client, &QMqttClient::pingResponseReceived, this, [this]() {
const QString content = QDateTime::currentDateTime().toString()
+ QLatin1String(" PingResponse")
+ QLatin1Char('\n');
ui->editLog->insertPlainText(content);
});

connect(ui->lineEditHost, &QLineEdit::textChanged, m_client, &QMqttClient::setHostname);
connect(ui->spinBoxPort, QOverload<int>::of(&QSpinBox::valueChanged), this, &MainWindow::setClientPort);
updateLogStateChange();
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::on_buttonConnect_clicked()
{
if (m_client->state() == QMqttClient::Disconnected) {
ui->lineEditHost->setEnabled(false);
ui->spinBoxPort->setEnabled(false);
ui->buttonConnect->setText(tr("Disconnect"));
m_client->connectToHost();
} else {
ui->lineEditHost->setEnabled(true);
ui->spinBoxPort->setEnabled(true);
ui->buttonConnect->setText(tr("Connect"));
m_client->disconnectFromHost();
}
}

void MainWindow::on_buttonQuit_clicked()
{
QApplication::quit();
}

void MainWindow::updateLogStateChange()
{
const QString content = QDateTime::currentDateTime().toString()
+ QLatin1String(": State Change")
+ QString::number(m_client->state())
+ QLatin1Char('\n');
ui->editLog->insertPlainText(content);
}

void MainWindow::brokerDisconnected()
{
ui->lineEditHost->setEnabled(true);
ui->spinBoxPort->setEnabled(true);
ui->buttonConnect->setText(tr("Connect"));
}

void MainWindow::setClientPort(int p)
{
m_client->setPort(p);
}

void MainWindow::on_buttonPublish_clicked()
{
if (m_client->publish(ui->lineEditTopic->text(), ui->lineEditMessage->text().toUtf8()) == -1)
QMessageBox::critical(this, QLatin1String("Error"), QLatin1String("Could not publish message"));
}

void MainWindow::on_buttonSubscribe_clicked()
{
auto subscription = m_client->subscribe(ui->lineEditTopic->text());
if (!subscription) {
QMessageBox::critical(this, QLatin1String("Error"), QLatin1String("Could not subscribe. Is there a valid connection?"));
return;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
我們直接編譯運行該示例:
broker.hivemq.com

在官方文檔中介紹,可以直接連接以下兩個服務器地址:


經測試,第一個地址連接不上,所以我們直接輸入第二個地址進行測試:broker.hivemq.com

輸入地址,點擊連接后就可以連接服務器,並且State變成了2就表示已經連上了。
然后點擊訂閱按鈕,表示要訂閱這個主題,在點擊發布,就可以收到信息了:

可以在多台電腦上進行測試,只要訂閱了同一個主題,那么一端發送消息,其他端就可以接收到相應的信息。

Qt官方提供了非常詳細的文檔介紹,大家可以去參考接口的使用,最主要使用的類是QMqttClient。


至此,Qt官方提供的MQTT封裝模塊使用介紹已經全部完了,下一篇將介紹一個第三方基於MQTT封裝的使用方式。
————————————————
版權聲明:本文為CSDN博主「luoyayun361」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/luoyayun361/article/details/104671603


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM