开发者

QNetworkReply emits error signal twice when ContentNotFoundError occures when event loop is started in error slot

开发者 https://www.devze.com 2023-04-10 08:42 出处:网络
Im using QtSDK 4.7.3 I am doing this in (void test()): mgr = new QNetworkAccessManager(); reply = mgr->get(QNetworkRequest(QUrl(\"http://developer.qt.nokia.com/fileNotExisting.txt\")));

Im using QtSDK 4.7.3

I am doing this in (void test()):

mgr = new QNetworkAccessManager();
reply = mgr->get(QNetworkRequest(QUrl("http://developer.qt.nokia.com/fileNotExisting.txt")));

connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
    SLOT(onError(QNetworkReply::NetworkError)), Qt::ConnectionType::UniqueConnection);

And of course the slot onError is called:

if (networkError == QNetworkReply::NetworkError::ContentNotFoundError)
{
// Messagebox starts an event loop which
// causes this slot to be called again
QMessageBox m;
m.exec();
}

If i don't have a messagebox/eventloop in the onError slot there is no crash and everything works. But when it is there then the onError slot gets called again when m.exec() is called. When both messageboxes are closed and I leave the function onError the application crashes. The application tries to delete/free memory when this happens. The error "Access violation reading location" does not help any and the call stack is deep in to Qt dlls.

What I have checked:

The signal is not connected twice.

Tried calling test() before and after the QApplication calls it's exec function. (does not matter).

Another error like HostNotFound will not call the onError slot twice.

All my code is executed in the main thread.

Tried disconnecting the onError slot so it is only called once but it still crashes.

Tried calling abort on the request in onError().

Posted the same question on Qt forum (post).

Can anyone help me figure out what is hap开发者_运维技巧pening here?

Here is the code I use for testing: main.cpp

#include "contentnotfound.h"
#include <QtGui/QApplication>
#include <QTimer>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

ContentNotFound cnf;

// false: start test after application's event loop have started
if (true) { cnf.test(); }
else { QTimer::singleShot(2000, &cnf, SLOT(test())); }

return a.exec();
}

contentnotfound.h

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QMessageBox>

class ContentNotFound : public QObject
{
Q_OBJECT

public slots:
void test()
{
    mgr = new QNetworkAccessManager();
    reply = mgr->get(QNetworkRequest(QUrl("http://developer.qt.nokia.com/fileNotExisting.txt")));

    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
        SLOT(onError(QNetworkReply::NetworkError)), Qt::ConnectionType::UniqueConnection);
}

private slots:
void onError(QNetworkReply::NetworkError networkError)
{
    //reply->disconnect(); // Disconnect all signals

    if (networkError == QNetworkReply::NetworkError::ContentNotFoundError)
    {
        // Messagebox starts an event loop which
        // causes this slot to be called again
        QMessageBox m;
        m.exec();
    }
}

private:
QNetworkAccessManager* mgr;
QNetworkReply* reply;

};


There is a bug in Qt < 4.8.0: https://bugreports.qt.io/browse/QTBUG-16333

Modifying the connection with a queued one solves the problem:

contentnotfound.h:

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QMessageBox>

class ContentNotFound : public QObject
{
Q_OBJECT

public slots:
void test()
{
    qRegisterMetaType<QNetworkReply::NetworkError>("QNetworkReply::NetworkError");
    mgr = new QNetworkAccessManager(this);
    reply = mgr->get(QNetworkRequest(QUrl("http://developer.qt.nokia.com/fileNotExisting.txt")));

    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
        SLOT(onError(QNetworkReply::NetworkError)), Qt::QueuedConnection);
}

private slots:
void onError(QNetworkReply::NetworkError networkError)
{
    //reply->disconnect(); // Disconnect all signals

    if (networkError == QNetworkReply::ContentNotFoundError)
    {
        // Messagebox starts an event loop which
        // causes this slot to be called again
        QMessageBox m;
        m.exec();
    }
}

private:
QNetworkAccessManager* mgr;
QNetworkReply* reply;

};
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号