为QNetworkAccessManager添加超时提醒

在做更新,在测试异常的时候,在下载过程中,发现如果直接系统禁用了网络,会报错误,可以捕获。但是如果是第三方软件限制程序联网,问题来了。

程序会一直在那里等待,没有异常,也不发送QNetworkAccessManager::finsh和QNetworkReply::error和QNetworkReply::finsh信号。

所以动念头为下载加个超时,但是QNetworkAccessManager,QNetworkReply和QNetworkRequest都没有相关的设置函数。其实仔细想一下,也没有办法直接提供超时,因为下载的文件有大有小,网络有快有慢,什么才算超时呢。只有自己想办法添加了。因为这个异常必须想办法发现并处理它,那么问题就必须要解决了。

先说下我的解决思路,利用QNetworkReply::downloadProgress 信号来实现,自己记录一段时间里的下载字节数,用定时器去定期检测,如果一段时间了,一点多余的下载都没有,那么我就认为网络超时异常了。

下面就上代码,自己简单用代码描述下:

声明:

class NetWorkDownload : public QObject
{
    Q_OBJECT
public:
    explicit NetWorkDownload(QObject *parent = 0);
signals:
    void timeOut();
    //····你的其他需要传递出去的信号
public slots:
    void startDownload(const QString & url);
    
protected slots:
    void handleReply(QNetworkReply * rep);//处理下载完成的数据
    void handSize(qint64 size, qint64 all);
    void handleTimeOut();
private:
    QNetworkAccessManager manger;
    int fileDownSize,//已经下载的字节数
        lastDownSize;//定时器上次下载的字节数
    QTimer tm;//定时器
};

实现:

NetWorkDownload::NetWorkDownload(QObject *parent) :
    QObject(parent)
{
    //这个connect你也可以用QNetworkReply来链接,QNetworkReply::finsh,QNetworkReply::readyReady这些信号。
    connect(&manger,&QNetworkAccessManager::finished,this,&NetWorkDownload::handleReply);
    connect(&tm,&QTimer::timeout,this,&NetWorkDownload::timeOut);
}

void NetWorkDownload::startDownload(const QString & url)
{
    QNetworkRequest req;
    req.setUrl(QUrl(url));
    auto rep = manger.get(req);
    connect(rep,&QNetworkReply::downloadProgress,this,&NetWorkDownload::handSize);
    //启动超时定时,30s。
    if (tm.isActive())
        tm.stop();
    tm.start(30000);
}

void NetWorkDownload::handSize(qint64 size,qint64 /* all*/)
{
    fileDownSize = size;
}

void NetWorkDownload::handleReply(QNetworkReply *rep)
{
    /*
    下载完成的您的处理代码。
    */
    fileDownSize = 0;
    lastDownSize = 0;
    if (tm.isActive())//如果还在定时,就停止
        tm.stop();
}

void NetWorkDownload::timeOut()
{
    if (lastDownSize != fileDownSize)//如果过了30s,一点字节也没有下载过来,认为超时了。
        lastDownSize = fileDownSize;
    else
        emit timeOut();
}

 

25 thoughts on “为QNetworkAccessManager添加超时提醒”

  1. QNetworkAccessManager manager_; QString url = QString(“https://api.shanbay.com/bdc/search/?word=%1”).arg(word); QNetworkRequest request; request.setUrl(QUrl(url)); QString tokenStr = QString(“Bearer %1”).arg(“kIFgt2b3QJwkmZ8hpi0QwvCCs6m59c”); request.setRawHeader(“Authorization”,tokenStr.toLatin1()); QNetworkReply* reply = manager_.get(request); QEventLoop loop; QObject::connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit())); QTimer::singleShot(3000, &loop, SLOT(quit())); loop.exec(); QByteArray data = reply->readAll(); if (!data.isEmpty()) { QString text = QString::fromUtf8(data); bool s = false; QtJson::JsonObject json = QtJson::parse(text, s).toMap(); if (s) { if (json.contains(“data”)) { QtJson::JsonObject dataObj = json[“data”].toMap(); QString cnValue = dataObj[“definition”].toString(); std::cout<< cnValue.toLocal8Bit().data() << std::endl; } QString myJson = QtJson::serializeStr(json); std::cout<< myJson.toLocal8Bit().data() << std::endl; makeTree(json); return myJson; } }//———————————————————————————//在知乎上看到你的回答,来你博客看一下。嘻嘻//我一般这样干,用eventloop来搞个同步 QNetworkReply* reply = manager_.get(request); QEventLoop loop; QObject::connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit())); QTimer::singleShot(3000, &loop, SLOT(quit())); loop.exec(); QByteArray data = reply->readAll(); if (!data.isEmpty()) { // somthing }

    1. 用QEventLoop 是最简单明了的方式、、但是在下载文件的时候,特别是连续下很多文件,你没法事先获取文件大小和用户的网络速度的,用这种估值的办法就不大现实了、、我这个是在做一个更新程序的时候遇到的,更新的文件中最大的一个是40多M的、、不能一次阻塞等他下完的、、就是放到单独线程中,时间也是不可估量的、、只有异步的方式处理、、、

  2. 确实是一个好的想法,学习了。
    此处,存在疑问,如果当前获取数据超时,那么应该怎样操作中断当前的数据获取呢?
    求教,谢谢!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.