QNetworkAccessManager not emitting readyRead or finished signal
-
hi, can anyone help to debug on this QNetworkAccessManager wrapper? I use a python flask application to receive on http://localhost:8000/ and return 200, "hello world", but when I call
session.get(QUrl{"http://localhost:8000/"}), it sucks on waiting for reply debug message and cannot go for no matterQNetworkReply::readyReadorQNetworkReply::finishedsignal, which cannot exit the loop.


.h:class session : public QObject { Q_OBJECT public: session(void); response get(QUrl url, QUrlQuery query = QUrlQuery(), std::map<QString, QVariant> headers = std::map<QString, QVariant>(), uint timeout_sec = 60); response post(QUrl url, JSON json = JSON(), std::map<QString, QVariant> headers = std::map<QString, QVariant>(), uint timeout_sec = 60); response post(QUrl url, QUrlQuery data = QUrlQuery(), std::map<QString, QVariant> headers = std::map<QString, QVariant>(), uint timeout_sec = 60); signals: void request_start_signal(void); public slots: void request_process_slot(void); private: QNetworkAccessManager manager; QByteArray request_data; MethodsEnum request_method; bool is_finished = true; bool is_running = false; QNetworkRequest* request = nullptr; QNetworkReply* reply = nullptr; response wait_for_reply(uint timeout_sec); };.cpp
session::session(void) { connect(this, &session::request_start_signal, this, &session::request_process_slot); } void session::request_process_slot(void) { qDebug() << "request slot"; this->is_running = true; switch (request_method) { case GET: this->reply = this->manager.get(*this->request); break; case POST: this->reply = this->manager.post(*this->request, this->request_data); break; default: break; } QEventLoop loop; connect(this->reply, &QNetworkReply::readyRead, &loop, &QEventLoop::quit); loop.exec(); qDebug() << "request slot finished"; this->is_finished = true; this->is_running = false; } response session::wait_for_reply(uint timeout_sec) { uint64_t start_time = QDateTime::currentMSecsSinceEpoch(); while (!this->is_finished) { // just do blocking request is fine for this project's case qDebug() << "waiting for reply" << (QDateTime::currentMSecsSinceEpoch() - start_time) / 1000; if (timeout_sec > 0 && QDateTime::currentMSecsSinceEpoch() - start_time > timeout_sec * 1000) { qDebug() << "request timeout"; this->is_finished = true; this->reply->disconnect(); delete this->reply; return response(); } QThread::msleep(100); } response res = response(this->request, this->reply); this->reply->disconnect(); delete this->request; this->request = nullptr; delete this->reply; this->reply = nullptr; return res; } response session::get(QUrl url, QUrlQuery query, std::map<QString, QVariant> headers, uint timeout_sec) { qDebug() << "GET"; while (!this->is_finished) { qDebug() << "waiting for prev request to finish"; QThread::msleep(100); } url.setQuery(query.query()); if (this->request != nullptr) { delete this->request; } this->request = new QNetworkRequest(url); qDebug() << 3; for (const auto& [key, value] : headers) { this->request->setRawHeader(key.toUtf8(), value.toByteArray()); } this->request_method = GET; this->is_finished = false; emit this->request_start_signal(); return this->wait_for_reply(timeout_sec); } -
hi, can anyone help to debug on this QNetworkAccessManager wrapper? I use a python flask application to receive on http://localhost:8000/ and return 200, "hello world", but when I call
session.get(QUrl{"http://localhost:8000/"}), it sucks on waiting for reply debug message and cannot go for no matterQNetworkReply::readyReadorQNetworkReply::finishedsignal, which cannot exit the loop.


.h:class session : public QObject { Q_OBJECT public: session(void); response get(QUrl url, QUrlQuery query = QUrlQuery(), std::map<QString, QVariant> headers = std::map<QString, QVariant>(), uint timeout_sec = 60); response post(QUrl url, JSON json = JSON(), std::map<QString, QVariant> headers = std::map<QString, QVariant>(), uint timeout_sec = 60); response post(QUrl url, QUrlQuery data = QUrlQuery(), std::map<QString, QVariant> headers = std::map<QString, QVariant>(), uint timeout_sec = 60); signals: void request_start_signal(void); public slots: void request_process_slot(void); private: QNetworkAccessManager manager; QByteArray request_data; MethodsEnum request_method; bool is_finished = true; bool is_running = false; QNetworkRequest* request = nullptr; QNetworkReply* reply = nullptr; response wait_for_reply(uint timeout_sec); };.cpp
session::session(void) { connect(this, &session::request_start_signal, this, &session::request_process_slot); } void session::request_process_slot(void) { qDebug() << "request slot"; this->is_running = true; switch (request_method) { case GET: this->reply = this->manager.get(*this->request); break; case POST: this->reply = this->manager.post(*this->request, this->request_data); break; default: break; } QEventLoop loop; connect(this->reply, &QNetworkReply::readyRead, &loop, &QEventLoop::quit); loop.exec(); qDebug() << "request slot finished"; this->is_finished = true; this->is_running = false; } response session::wait_for_reply(uint timeout_sec) { uint64_t start_time = QDateTime::currentMSecsSinceEpoch(); while (!this->is_finished) { // just do blocking request is fine for this project's case qDebug() << "waiting for reply" << (QDateTime::currentMSecsSinceEpoch() - start_time) / 1000; if (timeout_sec > 0 && QDateTime::currentMSecsSinceEpoch() - start_time > timeout_sec * 1000) { qDebug() << "request timeout"; this->is_finished = true; this->reply->disconnect(); delete this->reply; return response(); } QThread::msleep(100); } response res = response(this->request, this->reply); this->reply->disconnect(); delete this->request; this->request = nullptr; delete this->reply; this->reply = nullptr; return res; } response session::get(QUrl url, QUrlQuery query, std::map<QString, QVariant> headers, uint timeout_sec) { qDebug() << "GET"; while (!this->is_finished) { qDebug() << "waiting for prev request to finish"; QThread::msleep(100); } url.setQuery(query.query()); if (this->request != nullptr) { delete this->request; } this->request = new QNetworkRequest(url); qDebug() << 3; for (const auto& [key, value] : headers) { this->request->setRawHeader(key.toUtf8(), value.toByteArray()); } this->request_method = GET; this->is_finished = false; emit this->request_start_signal(); return this->wait_for_reply(timeout_sec); }@GaryL said in QNetworkAccessManager not emitting readyRead or finished signal:
QThread::msleep(100);
WTF?
Qt is async so post your request, return to the event loop and when the answer arrives Qt will call your slot.
-
hi, can anyone help to debug on this QNetworkAccessManager wrapper? I use a python flask application to receive on http://localhost:8000/ and return 200, "hello world", but when I call
session.get(QUrl{"http://localhost:8000/"}), it sucks on waiting for reply debug message and cannot go for no matterQNetworkReply::readyReadorQNetworkReply::finishedsignal, which cannot exit the loop.


.h:class session : public QObject { Q_OBJECT public: session(void); response get(QUrl url, QUrlQuery query = QUrlQuery(), std::map<QString, QVariant> headers = std::map<QString, QVariant>(), uint timeout_sec = 60); response post(QUrl url, JSON json = JSON(), std::map<QString, QVariant> headers = std::map<QString, QVariant>(), uint timeout_sec = 60); response post(QUrl url, QUrlQuery data = QUrlQuery(), std::map<QString, QVariant> headers = std::map<QString, QVariant>(), uint timeout_sec = 60); signals: void request_start_signal(void); public slots: void request_process_slot(void); private: QNetworkAccessManager manager; QByteArray request_data; MethodsEnum request_method; bool is_finished = true; bool is_running = false; QNetworkRequest* request = nullptr; QNetworkReply* reply = nullptr; response wait_for_reply(uint timeout_sec); };.cpp
session::session(void) { connect(this, &session::request_start_signal, this, &session::request_process_slot); } void session::request_process_slot(void) { qDebug() << "request slot"; this->is_running = true; switch (request_method) { case GET: this->reply = this->manager.get(*this->request); break; case POST: this->reply = this->manager.post(*this->request, this->request_data); break; default: break; } QEventLoop loop; connect(this->reply, &QNetworkReply::readyRead, &loop, &QEventLoop::quit); loop.exec(); qDebug() << "request slot finished"; this->is_finished = true; this->is_running = false; } response session::wait_for_reply(uint timeout_sec) { uint64_t start_time = QDateTime::currentMSecsSinceEpoch(); while (!this->is_finished) { // just do blocking request is fine for this project's case qDebug() << "waiting for reply" << (QDateTime::currentMSecsSinceEpoch() - start_time) / 1000; if (timeout_sec > 0 && QDateTime::currentMSecsSinceEpoch() - start_time > timeout_sec * 1000) { qDebug() << "request timeout"; this->is_finished = true; this->reply->disconnect(); delete this->reply; return response(); } QThread::msleep(100); } response res = response(this->request, this->reply); this->reply->disconnect(); delete this->request; this->request = nullptr; delete this->reply; this->reply = nullptr; return res; } response session::get(QUrl url, QUrlQuery query, std::map<QString, QVariant> headers, uint timeout_sec) { qDebug() << "GET"; while (!this->is_finished) { qDebug() << "waiting for prev request to finish"; QThread::msleep(100); } url.setQuery(query.query()); if (this->request != nullptr) { delete this->request; } this->request = new QNetworkRequest(url); qDebug() << 3; for (const auto& [key, value] : headers) { this->request->setRawHeader(key.toUtf8(), value.toByteArray()); } this->request_method = GET; this->is_finished = false; emit this->request_start_signal(); return this->wait_for_reply(timeout_sec); }@GaryL said in QNetworkAccessManager not emitting readyRead or finished signal:
QThread::msleep(100)
no event handling, no signals, no slots being called
while (!this->is_finished)
same here
-
@Christian-Ehrlicher @J-Hilk
Thanks for your help, but the problem is in function
request_process_slot, not in functionwait_for_reply.I have used a QEventLoop loop to block the process, and connect it with
connect(this->reply, &QNetworkReply::readyRead, &loop, &QEventLoop::quit);. but then not matter I useQNetworkReply::readyReadorQNetworkReply::finishedas signal, it still sucks on this event loop.I have
connect(this, &session::request_start_signal, this, &session::request_process_slot);in the constructor, so request_process_slot can be called whenemit this->request_start_signal();in get function. -
@Christian-Ehrlicher @J-Hilk
Thanks for your help, but the problem is in function
request_process_slot, not in functionwait_for_reply.I have used a QEventLoop loop to block the process, and connect it with
connect(this->reply, &QNetworkReply::readyRead, &loop, &QEventLoop::quit);. but then not matter I useQNetworkReply::readyReadorQNetworkReply::finishedas signal, it still sucks on this event loop.I have
connect(this, &session::request_start_signal, this, &session::request_process_slot);in the constructor, so request_process_slot can be called whenemit this->request_start_signal();in get function.@GaryL said in QNetworkAccessManager not emitting readyRead or finished signal:
I have used a QEventLoop loop to block the process
No!
Go back to the Qt event loop.
-
@GaryL said in QNetworkAccessManager not emitting readyRead or finished signal:
I have used a QEventLoop loop to block the process
No!
Go back to the Qt event loop.
@Christian-Ehrlicher umm... not really understand, you mean sth like this?
session::session(void) { connect(this, &session::request_start_signal, this, &session::request_process_slot); } void session::request_process_slot(void) { qDebug() << "request slot"; this->is_running = true; switch (request_method) { case GET: this->reply = this->manager.get(*this->request); break; case POST: this->reply = this->manager.post(*this->request, this->request_data); break; default: break; } } response session::wait_for_reply(uint timeout_sec) { while (this->reply == nullptr) { QThread::msleep(10); } QEventLoop loop; connect(this->reply, &QNetworkReply::readyRead, &loop, &QEventLoop::quit); loop.exec(); this->is_finished = true; response res = response(this->request, this->reply); this->reply->disconnect(); delete this->request; this->request = nullptr; delete this->reply; this->reply = nullptr; return res; } response session::get(QUrl url, QUrlQuery query, std::map<QString, QVariant> headers, uint timeout_sec) { qDebug() << "GET"; while (!this->is_finished) { qDebug() << "waiting for prev request to finish"; QThread::msleep(100); } url.setQuery(query.query()); if (this->request != nullptr) { delete this->request; } this->request = new QNetworkRequest(url); for (const auto& [key, value] : headers) { this->request->setRawHeader(key.toUtf8(), value.toByteArray()); } this->request_method = GET; this->is_finished = false; emit this->request_start_signal(); return this->wait_for_reply(timeout_sec); } -
@Christian-Ehrlicher umm... not really understand, you mean sth like this?
session::session(void) { connect(this, &session::request_start_signal, this, &session::request_process_slot); } void session::request_process_slot(void) { qDebug() << "request slot"; this->is_running = true; switch (request_method) { case GET: this->reply = this->manager.get(*this->request); break; case POST: this->reply = this->manager.post(*this->request, this->request_data); break; default: break; } } response session::wait_for_reply(uint timeout_sec) { while (this->reply == nullptr) { QThread::msleep(10); } QEventLoop loop; connect(this->reply, &QNetworkReply::readyRead, &loop, &QEventLoop::quit); loop.exec(); this->is_finished = true; response res = response(this->request, this->reply); this->reply->disconnect(); delete this->request; this->request = nullptr; delete this->reply; this->reply = nullptr; return res; } response session::get(QUrl url, QUrlQuery query, std::map<QString, QVariant> headers, uint timeout_sec) { qDebug() << "GET"; while (!this->is_finished) { qDebug() << "waiting for prev request to finish"; QThread::msleep(100); } url.setQuery(query.query()); if (this->request != nullptr) { delete this->request; } this->request = new QNetworkRequest(url); for (const auto& [key, value] : headers) { this->request->setRawHeader(key.toUtf8(), value.toByteArray()); } this->request_method = GET; this->is_finished = false; emit this->request_start_signal(); return this->wait_for_reply(timeout_sec); } -
@GaryL
As the other two responders have said, you must not use either ofwhile (!this->is_finished) QThread::msleep(100)They go against how an event-driven framework like Qt works.
@JonB I am doing is because I original use qDebug() to print the variables of
this->replyinside the loop so to find out what is going on, but it turns out that all variables seems normal. On the other hand, the python flask script do have receive a request and returned 200, "Hello world", so I don't know what is actually going on... -
@JonB I am doing is because I original use qDebug() to print the variables of
this->replyinside the loop so to find out what is going on, but it turns out that all variables seems normal. On the other hand, the python flask script do have receive a request and returned 200, "Hello world", so I don't know what is actually going on...@GaryL
At this point I would suggest you dump calling your code, especiallywait_for_reply(), for a while. Just produce a minimal program withoutwhile,is_finished,msleep,QEventLoopetc. Just connect the reply'sreadyRead()to something which outputs whatever it receives, do yourget()orpost()and verify you get the returned result (without "waiting" for it). -
@JonB I am doing is because I original use qDebug() to print the variables of
this->replyinside the loop so to find out what is going on, but it turns out that all variables seems normal. On the other hand, the python flask script do have receive a request and returned 200, "Hello world", so I don't know what is actually going on...@GaryL said in QNetworkAccessManager not emitting readyRead or finished signal:
so I don't know what is actually going on...
again, you're blocking any and all event handling in your qt application. The OS doesn't care about that and forwards your requests, thats why you may see stuff on the other side.
Btw, the Pythonfyed c++ is hurting my soul :P, deeply
-
@GaryL
At this point I would suggest you dump calling your code, especiallywait_for_reply(), for a while. Just produce a minimal program withoutwhile,is_finished,msleep,QEventLoopetc. Just connect the reply'sreadyRead()to something which outputs whatever it receives, do yourget()orpost()and verify you get the returned result (without "waiting" for it).@JonB @J-Hilk I have actually used another url which is https://accounts.spotify.com/api/token, this url can be successfully exceuted with the above code and get its return json, but the same code fails with http://localhost:8000/ or https://api.spotify.com/v1/me/player/currently-playing