英文:
How to know when GET request is finished with QNetworkAccessManager
问题
How do you know when QNetworkAccessManager GET request is finished? Is there a signal it emits or a way to busy wait until the request is finished? I currently have a QTimer set for 300ms for waiting.
#include <QApplication>
Downloader::Downloader(QApplication *app) {
manager = new QNetworkAccessManager(app);
}
void Downloader::TestConnection(QString theUrl) const {
auto status = connect(manager, &QNetworkAccessManager::finished, this, &Downloader::ReplyFinished);
manager->get(QNetworkRequest(QUrl(theUrl)));
}
void Downloader::ReplyFinished(QNetworkReply *reply) {
theNetworkData = reply->readAll();
}
QString Downloader::getNetworkData() {
return theNetworkData;
}
And in the main file:
auto downloaderObject = new Downloader(qApp);
downloaderObject->TestConnection("http://theurl");
// Delay 300ms for network reply
QEventLoop loop;
QTimer::singleShot(300, &loop, &QEventLoop::quit);
loop.exec();
networkAnswer = downloaderObject->getNetworkData();
Note: I've removed the HTML encoding (&
) from the code for readability, but in the actual code, you should keep the correct encoding.
英文:
How do you know when QNetworkAcessManager GET request is finished? Is there a signal it emits or a way to busy wait until the request is finished? I currently have a QTimer set for 300ms for waiting.
#include <QApplication>
Downloader::Downloader(QApplication *app) {
manager = new QNetworkAccessManager(app);
}
void Downloader::TestConnection(QString theUrl) const {
auto status = connect(manager, &QNetworkAccessManager::finished, this, &Downloader::ReplyFinished);
manager->get(QNetworkRequest(QUrl(theUrl)));
}
void Downloader::ReplyFinished(QNetworkReply *reply) {
theNetworkData = reply->readAll();
}
QString Downloader::getNetworkData() {
return theNetworkData;
}
And in the main file:
auto downloaderObject = new Downloader(qApp);
downloaderObject->TestConnection("http://theurl");
// Delay 300ms for network reply
QEventLoop loop;
QTimer::singleShot(300, &loop, &QEventLoop::quit);
loop.exec();
networkAnswer = downloaderObject->getNetworkData();
答案1
得分: 2
以下是您要翻译的内容:
获取请求将发送“已完成”信号,您已经与以下代码连接到它:
connect(manager, &QNetworkAccessManager::finished, this, &Downloader::ReplyFinished);
让我感到困惑的部分是关于使用计时器等待... 然后我明白了,您基本上想要发起一个GET请求,设置一个延迟并“希望”在延迟到期之前完成GET请求。
我编写了大约15分钟的代码,所以它可能不太美观,但它实现了您的要求(我想!)。
Downloader.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include
class QNetworkConfiguration;
class QNetworkAccessManager;
class QNetworkConfigurationManager;
class QNetworkReply;
class QNetworkSession;
class Downloader : public QObject
{
Q_OBJECT
public:
explicit Downloader(QObject *parent = nullptr);
~Downloader();
bool open_network_connection();
bool is_finished();
void TestConnection(QString) const;
QString getNetworkData();
private slots:
void ReplyFinished(QNetworkReply *reply);
signals:
private:
QNetworkAccessManager* m_network_manager;
QNetworkReply* m_reply;
QNetworkConfigurationManager *m_configuration_manager;
QNetworkSession *m_session;
QString theNetworkData;
bool can_start_iap;
bool finished;
};
#endif // DOWNLOADER_H
Downloader.cpp
#include
#include
#include
#include
#include
#include "downloader.h"
Downloader::Downloader(QObject *parent)
: QObject{parent}
, m_network_manager(new QNetworkAccessManager(this))
, m_configuration_manager(new QNetworkConfigurationManager(this))
{
finished = false;
QObject::connect(m_network_manager, &QNetworkAccessManager::finished, this, &Downloader::ReplyFinished);
}
Downloader::~Downloader() {
delete m_network_manager;
delete m_configuration_manager;
delete m_session;
}
bool Downloader::open_network_connection() {
can_start_iap = (m_configuration_manager->capabilities() &
QNetworkConfigurationManager::CanStartAndStopInterfaces);
QNetworkConfiguration m_configuration = m_configuration_manager->defaultConfiguration();
if(!m_configuration.isValid() || (!can_start_iap && m_configuration.state() != QNetworkConfiguration::Active)) {
return false;
}
else {
finished = false;
m_session = new QNetworkSession(m_configuration);
m_session->open();
return m_session->waitForOpened(-1);
}
}
void Downloader::TestConnection(QString theUrl) const {
m_network_manager->get(QNetworkRequest(QUrl(theUrl)));
}
void Downloader::ReplyFinished(QNetworkReply *reply) {
if(reply->error() == QNetworkReply::NoError) {
theNetworkData = QString(reply->readAll());
}
else {
theNetworkData = QString("Network Error");
}
finished = true;
}
QString Downloader::getNetworkData() {
return theNetworkData;
}
bool Downloader::is_finished() {
return finished;
}
Main.cpp
#include
#include
#include
#include "downloader.h"
void delay( int millisecondsToWait );
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Downloader *downloaderObject = new Downloader(nullptr);
if (downloaderObject->open_network_connection()) {
downloaderObject->TestConnection("
while(!downloaderObject->is_finished()) {
delay(1000);
}
qDebug() << downloaderObject->getNetworkData();
}
else {
qDebug() << "Error";
}
delete downloaderObject;
return a.exec();
}
void delay( int millisecondsToWait )
{
QTime dieTime = QTime::currentTime().addMSecs( millisecondsToWait );
while( QTime::currentTime() < dieTime )
{
QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
}
}
.pro文件(基于Ubuntu 20.04)
QT += core gui
QT += network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17 console
CONFIG -= app_bundle
如果代码使用了已弃用的API,则可以使其无法编译。要这样做,请取消注释以下行。
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # 禁用Qt 6.0.0之前已弃用的所有API
SOURCES +=
downloader.cpp
main.cpp
默认的部署规则。
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS +=
downloader.h
请注意,这些代码可能需要进行更多的错误检查和验证,以适应实际需求。这只是一个基本示例,用于演示您想要实现的功能。希望这对您有所帮助。
英文:
The get request will send the "Finished" signal, which you have already hooked into with the line:
connect(manager, &QNetworkAccessManager::finished, this, &Downloader::ReplyFinished);
The bit that confused me was the part about waiting with a timer... Then it clicked, your basically wanting to initiate a GET, set a delay and "hope" that the GET finishes before the delay expires.
Most apps I have written use the GET within a GUI of some sort, and therefore it is all signal driven and no need to wait as such. But on the basis that you are wanting to "delay" whilst allowing the Finished signal to be emitted, the following code will do that...
I knocked it together in about 15 minutes so it's not pretty, but it does what you were asking (I think!).
Downloader.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QObject>
class QNetworkConfiguration;
class QNetworkAccessManager;
class QNetworkConfigurationManager;
class QNetworkReply;
class QNetworkSession;
class Downloader : public QObject
{
Q_OBJECT
public:
explicit Downloader(QObject *parent = nullptr);
~Downloader();
bool open_network_connection();
bool is_finished();
void TestConnection(QString) const;
QString getNetworkData();
private slots:
void ReplyFinished(QNetworkReply *reply);
signals:
private:
QNetworkAccessManager* m_network_manager;
QNetworkReply* m_reply;
QNetworkConfigurationManager *m_configuration_manager;
QNetworkSession *m_session;
QString theNetworkData;
bool can_start_iap;
bool finished;
};
#endif // DOWNLOADER_H
Downloader.cpp
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkConfigurationManager>
#include <QNetworkSession>
#include "downloader.h"
Downloader::Downloader(QObject *parent)
: QObject{parent}
, m_network_manager(new QNetworkAccessManager(this))
, m_configuration_manager(new QNetworkConfigurationManager(this))
{
finished = false;
QObject::connect(m_network_manager, &QNetworkAccessManager::finished, this, &Downloader::ReplyFinished);
}
Downloader::~Downloader() {
delete m_network_manager;
delete m_configuration_manager;
delete m_session;
}
bool Downloader::open_network_connection() {
can_start_iap = (m_configuration_manager->capabilities() &
QNetworkConfigurationManager::CanStartAndStopInterfaces);
QNetworkConfiguration m_configuration = m_configuration_manager->defaultConfiguration();
if(!m_configuration.isValid() || (!can_start_iap && m_configuration.state() != QNetworkConfiguration::Active)) {
return false;
}
else {
finished = false;
m_session = new QNetworkSession(m_configuration);
m_session->open();
return m_session->waitForOpened(-1);
}
}
void Downloader::TestConnection(QString theUrl) const {
m_network_manager->get(QNetworkRequest(QUrl(theUrl)));
}
void Downloader::ReplyFinished(QNetworkReply *reply) {
if(reply->error() == QNetworkReply::NoError) {
theNetworkData = QString(reply->readAll());
}
else {
theNetworkData = QString("Network Error");
}
finished = true;
}
QString Downloader::getNetworkData() {
return theNetworkData;
}
bool Downloader::is_finished() {
return finished;
}
And Main.cpp
#include <QApplication>
#include <QDebug>
#include <QTime>
#include "downloader.h"
void delay( int millisecondsToWait );
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Downloader *downloaderObject = new Downloader(nullptr);
if (downloaderObject->open_network_connection()) {
downloaderObject->TestConnection("<Enter a valid URL here>");
while(!downloaderObject->is_finished()) {
delay(1000);
}
qDebug() << downloaderObject->getNetworkData();
}
else {
qDebug() << "Error";
}
delete downloaderObject;
return a.exec();
}
void delay( int millisecondsToWait )
{
QTime dieTime = QTime::currentTime().addMSecs( millisecondsToWait );
while( QTime::currentTime() < dieTime )
{
QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
}
}
the .pro file (ubuntu 20.04 based)
QT += core gui
QT += network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17 console
CONFIG -= app_bundle
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
downloader.cpp \
main.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += \
downloader.h
Like I say, this was knocked together pretty quick, there could be lots more error checking, validation, etc and it's not necessarily how I would write it at work but it shows what I think you were trying to achieve.
Compiles and runs on QT Creator 9.0.2, QT 5.12.8
答案2
得分: 1
Both QNetworkAccessManager and QNetworkReply have finished signals:
- https://doc.qt.io/qt-6/qnetworkaccessmanager.html
- https://doc.qt.io/qt-6/qnetworkreply.html#finished
And I see you already used it.
You can find an example here: https://github.com/carlonluca/lqtutils/blob/master/lqtutils_net.cpp#L99. That class downloads a file and emits a signal when done, pretty similar to what you need.
英文:
Both QNetworkAccessManager and QNetworkReply have finished signals:
- https://doc.qt.io/qt-6/qnetworkaccessmanager.html
- https://doc.qt.io/qt-6/qnetworkreply.html#finished
And I see you already used it.
You can find an example here: https://github.com/carlonluca/lqtutils/blob/master/lqtutils_net.cpp#L99. That class downloads a file and emits a signal when done, pretty similar to what you need.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论