要实现在子线程中使用qtmqtt的客户端来发送和接收消息
问题:
在主线程创建一个客户端,子线程使用主线程创建的客户端,会无法通信的
// 发布线程2,共用主线程的客户端,会出现报错:QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
QThread* thread2 = new QThread();
Publish* publish = new Publish(m_client); // m_client 对象是在主线程创建的,
publish->moveToThread(thread2);
原因: 在主线程创建的 m_client
无法在子线程中使用,只能在创建的线程中使用
解决:
参考:https://forum.qt.io/topic/109138/qmqttclient-connection-not-made-from-another-thread/9
核心思路:要在子线程中创建 客户端 QMqttClient *m_client
示例代码:
- publish.h
#ifndef PUBLISH_H
#define PUBLISH_H
#include <QObject>
#include "QtMqtt/qmqttclient.h"
class Publish :public QObject
{
Q_OBJECT
public:
Publish(QObject *parent);
Publish();
public slots:
void messagePublish();
void init();
void topicSubscribe();
void printReceiveMsg();
private:
QMqttClient *m_client;
QString message;
};
#endif // PUBLISH_H
- publish.cpp
#include "publish.h"
#include <QThread>
// 创建时就创建线程
Publish::Publish(QObject *parent): QObject(parent)
{
m_client = new QMqttClient();
m_client->setHostname("127.0.0.1");
m_client->setPort(1883);
m_client->connectToHost();
message = "main thread message!";
}
// 初始化客户端
void Publish::init()
{
m_client = new QMqttClient();
m_client->setHostname("127.0.0.1");
m_client->setPort(1883);
m_client->connectToHost();
message = "init message!";
}
// 这个空的用来创建对象,放到QThread中
Publish::Publish()
{
}
// 发布消息
void Publish::messagePublish()
{
qDebug() << "publishThread run : m_client state: " << m_client->state() << " (thread: " << QThread::currentThreadId() << " )";
QString topic = "qtmqtt/topic1";
if (m_client->publish(topic, message.toUtf8()) == -1)
{
qDebug() << "publish : Could not publish message" << " (thread: " << QThread::currentThreadId() << " )";
}else{
qDebug() << "publish ok!";
}
}
// 订阅主题
void Publish::topicSubscribe()
{
qDebug() << "publishThread run : m_client state: " << m_client->state() << " (thread: " << QThread::currentThreadId() << " )";
QString topic = "qtmqtt/topic1";
auto subscription = m_client->subscribe(topic);
if (!subscription) {
qDebug() << QLatin1String("Could not subscribe. Is there a valid connection?");
return;
}else{
qDebug() << "subcribe ok! " << " (thread: " << QThread::currentThreadId() << " )";
}
}
// 接收到消息,就打印出来
void Publish::printReceiveMsg()
{
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');
qDebug() << content << " (thread: " << QThread::currentThreadId() << " )";
});
}
- 使用
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() << "main thread: " << QThread::currentThreadId() << " )";
Publish * publish = new Publish(this);
connect(ui->pushButton ,&QPushButton::clicked,publish,&Publish::messagePublish);
// 子线程创建客户端
QThread * thread = new QThread;
Publish *publishClient = new Publish(); // 创建时不连接线程,
publishClient->moveToThread(thread);
connect(thread, &QThread::started, publishClient, &Publish::init); // init连接线程,在子线程里创建客户端,并连接进行连接客户端,
thread->start();
connect(ui->publishButton_2_start,&QPushButton::clicked,publishClient,&Publish::messagePublish); // 子线程发布消息
connect(ui->publishButton2_subscribe,&QPushButton::clicked,publishClient,&Publish::topicSubscribe); // 子线订阅消息
connect(ui->publishButton2_receive,&QPushButton::clicked,publishClient,&Publish::printReceiveMsg); // 子线程接收数据
// 子线程定时 2000ms发送一次消息
QTimer* timer = new QTimer(this);
// 不能使用lambda表达式
// QObject::connect(timer, &QTimer::timeout, [publishClient]() {
// publishClient->messagePublish();
// qDebug() << "Thread timer " <<QThread::currentThread();});
connect(timer,&QTimer::timeout,publishClient,&Publish::messagePublish);
// timer->setSingleShot(true); //设置为true之后,就会只触发一次
timer->start(2000);
}