MQTT Connection Problem
-
Hello everybody, I need some help with QtMqtt library.
I'm trying to code a program that takes in input hostname, port and topic and starts publishing messages in that topic.
The problem I am encountering is that once i try to connect with "m_client->connectToHost" it doesn't connect at all, and stays in "Connecting" state.
Do anybody have some advices?
This is my function:
#include "client.h" #include <QDebug> #include <QMqttTopicName> #include <iostream> #include <QObject> Client::Client(QObject *parent) : QObject{parent} {} void makeConnection(); void Client::setup(){ qint16 port; m_client = new QMqttClient(this); std::cout << "Inserisci l'hostname: "; QTextStream host(stdin); QString phrase1 = host.readLine(); m_client->setHostname(phrase1); qDebug() << "l'hostname settato è: "<<m_client->hostname(); std::cout << "Inserisci la porta: "; std::cin >> port; std::cin.ignore(); m_client->setPort(port); qDebug() << "la porta settata è: "<<m_client->port(); makeConnection(); qDebug() << "porta e host settati."; qDebug() << m_client->state(); std::cout << "Inserisci il topic: "; QTextStream tpc(stdin); const QString &indirizzoTpc = tpc.readLine(); while(true){ std::cout << "inserisci il messaggio da mandare: "; QTextStream msg(stdin); const auto &message = msg.readLine(); if(message == "termine") break; m_client->publish(QMqttTopicName(indirizzoTpc), message.toUtf8()); qDebug() << "messaggio inviato nel topic:\n" << indirizzoTpc; } exit(0); } void Client::makeConnection(){ m_client->connectToHost(); std::cout << "Client in connessione...\n"; }
Along with the header:
#ifndef CLIENT_H #define CLIENT_H #include <QObject> #include <QtMqtt/QMqttClient> class Client : public QObject { Q_OBJECT public: explicit Client(QObject *parent = nullptr); void setup(); QMqttClient *m_client; void makeConnection(); signals: void connessione_effettuata(); public slots: }; #endif // CLIENT_H
-
Hello @unamlositp, and welcome!
For a quick sanity check, please run the official Simple MQTT Client example: https://doc.qt.io/qt-6/qtmqtt-simpleclient-example.html Does this work for you?
-
@unamlositp said in MQTT Connection Problem:
i try to connect with "m_client->connectToHost" it doesn't connect at all, and stays in "Connecting" state.
@unamlositp said in MQTT Connection Problem:
while(true ) { std::cout << "inserisci il messaggio da mandare: "; QTextStream msg(stdin); const auto &message = msg.readLine(); if(message == "termine") break; m_client->publish(QMqttTopicName(indirizzoTpc), message.toUtf8()); qDebug() << "messaggio inviato nel topic:\n" << indirizzoTpc; } exit(0);
I wonder why 🤔
while(true)
without any multithreading is the worst thing you can do in an event based framework like Qt.
Your code stops the Qt internal event loop from working, so no events or signals (that, for example, a state has changed) are transmitted.
And don't even think about adding a thread to your app - you don't need it, sinceQMQTT
works just fine using Qt Signals and async functions.Do anybody have some advices?
It seems like you are lacking a lot C++ knowledge.
Get familiar with C++ basics, learn the principles of Qt (Signals & Slots, Qt Event System, Meta Object, QObject Tree) and then come back to your app.
You don't have to, but it helps a lot and you will make fewer “rookie mistakes”, like usingwhile
loops in the wrong places and therefore completely blocking your app.void makeConnection();
What is this free-floating function call/definition above
void Client::setup()
in your client.cpp?exit(0);
What is this? What are you expecting from this inside a member function?
-
-
@unamlositp said in MQTT Connection Problem:
@JKSH Hello, thanks for replying. I tried it before starting my personal one, and it does work
Then I recommend you study the code in that example and adapt it for your own project.
@Pl45m4 has correctly identified that your infinite
while()
loop blocks your event loop, and this prevents your connection from proceeding.After you call
m_client->connectToHost();
all of your functions must return so that the event loop can process the connection. Don't try to do anything else until theconnected()
signal is emitted: https://doc.qt.io/qt-6/qmqttclient.html#connectedP.S. You should familiarize yourself with Qt's signals and slots first
-
@Pl45m4 Hi, thanks for answering my question.
You're actually right, this is my first time dealing with C++ and Qt, i'm still trying to figure out the correct way to improve my code.
Thanks for the advices, i'll for sure focus more on getting basic knowledge of the language and the framework.@Pl45m4 said in MQTT Connection Problem:
What is this? What are you expecting from this inside a member function?
I used that instruction to completely end the program when i typed the keyword "termine", maybe i should put it in main function.
@Pl45m4 said in MQTT Connection Problem:
while(true) without any multithreading is the worst thing you can do in an event based framework like Qt.
Your code stops the Qt internal event loop from working, so no events or signals (that, for example, a state has changed) are transmitted.
And don't even think about adding a thread to your app - you don't need it, since QMQTT works just fine using Qt Signals and async functions.Thanks for the feedback, I'll try to make it better by using Signals and Slots, never thought about "blocking" my code with that function.
Sorry for replying so late, but i'm limited to 1 answer each hour :(
-
@unamlositp said in MQTT Connection Problem:
I used that instruction to completely end the program when i typed the keyword "termine", maybe i should put it in main function.
You should send a signal connected to appropriate slot in your QCoreApplication/QGuiApplication to properly exit the program. Not much of a problem in a simple program but an opportunity to imprint the right habits.
-
@Pl45m4 As you adviced me I tried removing the loops, and using signals instead.
I also created some classes, one for each feature I want my program to have, but I still can't get it right.
I read on documentation that "QMqttClient::connected()" is a signal sent when the client is successfully connected to the host, but there's still something i'm missing, because I still can't use it correctly. When i try to use it in a "connect" function, it gives me back the error you can see in the image below:
I tried my own implementation, but still not success at all. These are my functions now:
https://drive.google.com/file/d/1GamXYJo1XufG94AD24Xa1UOF2zJ1XkBz/view?usp=sharing
(I know it's a gDrive file, but if i paste code here it gets flagged as spam, I don't know why, forgive me for this)
I know I'm missing something, but I can't get to the point where i understand what's I'm actually doing bad.
-
client
is not aQMqttClient
subclass, it's aQObject
suclass so it doesn't have theconnected
signal.Also,
Client::MakeConnection()
still shows you didn't grasp the async nature of the class yet. you can't call a method to connect/write and rely on the operation being completed on the next instruction, the operation will be scheduled and done later, you should wait for the corresponding signal.P.S.
pastebin.com for short snippets of code
github.com for multi-file code sharing -
I would connect the
QMQTT
things inClient
class itself. There you have direct access to the object.
Your client then acts as wrapper forQMqttClient
.
Only expose functions to "control" the client to the outside...
So in yourmain.cpp
you goclient.start()
(or init() or Setup() or whatever you call it) and let the client handle the rest.Something like:
(Within your Client Constructor)Client::Client(QObject *parent) : QObject{parent} { connect(m_client, &QMqttClient::connected, this, &Client::handleConnection); }
Add some slot or function to do what you want to do as soon as you are connected.
Look at the example again what @JKSH linked above. It might give you some inspiration what you can do.
@VRonin said in MQTT Connection Problem:
pastebin.com for short snippets of code
Or add it to </> Code Section directly in the post.
-
@Pl45m4 said in MQTT Connection Problem:
I would connect the QMQTT things in Client class itself. There you have direct access to the object.
Your client then acts as wrapper for QMqttClient.
Only expose functions to "control" the client to the outside...
So in your main.cpp you go client.start() (or init() or Setup() or whatever you call it) and let the client handle the rest.Something like:
(Within your Client Constructor)I tried this approach, but no success, the result is still the same: it gets locked here
It seems like it gets stuck, even after calling that part of the function with a signal.
EDIT:
I added some lines before the m_client->connectToHost() one, just to know if the code actually gets there, and it does.void Client::MakeConnection(){ qDebug()<< "la funzione è stata chiamata" << "\nl'host è ancora: "<< m_client->hostname() <<"\nla porta è ancora: "<< m_client->port(); m_client->connectToHost(); if (m_client->state()==QMqttClient::Connected){ emit ConnessoConSuccesso(); } }
It just gets stuck:
-
@unamlositp said in MQTT Connection Problem:
m_client->connectToHost(); if (m_client->state()==QMqttClient::Connected){ emit ConnessoConSuccesso(); }
I have never used MQTT and don't know what it is. But void QMqttClient::connectToHost() says:
Initiates a connection to the MQTT broker.
It initiates a connection but does not wait for completion. You need to attach a slot to void QMqttClient::connected() to know when connection completes. It's too early to test for
QMqttClient::Connected
on the following line.Please read @VRonin's post above where he explained exactly this.
-
@unamlositp said in MQTT Connection Problem:
It seems like it gets stuck, even after calling that part of the function with a signal.
It's still not used in a clean way.
Just look at the example program here:
It has a GUI, but you can take the initialization part for your console program as well.
To check the connection and to play around with it, you don't need more than this:
client.h
#ifndef CLIENT_H #define CLIENT_H #include <QObject> #include <QtMqtt/QMqttClient> class Client : public QObject { Q_OBJECT public: explicit Client(QObject *parent = nullptr); void setup(); public slots: void onStateChanged(); private: QMqttClient *m_client; }; #endif // CLIENT_H
client.cpp
#include "client.h" #include <iostream> Client::Client(QObject *parent) : QObject{parent} { m_client = new QMqttClient(this); connect(m_client, &QMqttClient::stateChanged, this, &Client::onStateChanged); // setup(); } void Client::setup() { // hostname: std::cout << "\ninserire l'hostname: "; QTextStream host(stdin); QString Shost = host.readLine(); // port: qint16 p; std::cout << "\ninserire la porta: "; std::cin >> p; std::cin.ignore(); m_client->setHostname(Shost); m_client->setPort(static_cast<quint16>(p)); // Try to connect m_client->connectToHost(); } void Client::onStateChanged(QMqttClient::ClientState state) { switch(state) { case QMqttClient::Connected: qDebug() << "Connected: " << m_client->hostname() << ":" << m_client->port(); break; case QMqttClient::Connecting: qDebug() << "Attempting to connect: " << m_client->hostname() << ":" << m_client->port(); break; case QMqttClient::Disconnected: qDebug() << "Disconnected"; break; } }
main.cpp
#include <QCoreApplication> #include "client.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Client client; client.setup(); return a.exec(); }
@JonB said in MQTT Connection Problem:
I have never used MQTT and don't know what it is
Network client-server protocol to transmit tiny messages through a network. Nowadays mainly used for IoT device communication, in Industrial 4.0 or in robotics.