Qt之处理QNetworkAccessManager网络连接超时

来自:一去、二三里,https://blog.csdn.net/liang19890820/article/details/53204396

简述

在网络操作中,经常会由于各种原因引起网络连接超时,究竟何为网络连接超时?

网络连接超时:在程序默认的等待时间内没有得到服务器的响应

超时原因

引起网络连接超时的原因很多,下面,列举一些常见的原因:

  • 网络断开,不过经常显示无法连接
  • 网络阻塞,导致你不能在程序默认等待时间内得到回复数据包
  • 网络不稳定,网络无法完整传送服务器信息
  • 系统问题,系统资源过低,无法为程序提供足够的资源处理服务器信息
  • 设备不稳定,如网线松动、接口没插好等等
  • 网络注册时系统繁忙,无法回应
  • 网速过慢,如 使用 BT 多线程下载,在线收看视频等大量占用带宽的软件 ,若使用共享带宽还要防范他人恶意占用带宽
  • 计算机感染了恶意软件,计算机病毒,计算机木马等

Qt 中的网络连接超时

在 Qt 中,关于 QNetworkAccessManager、QNetworkRequest 和 QNetworkReply的文档中,找到了有关超时相关的错误 QNetworkReply::NetworkError。

常量 QNetworkReply::TimeoutError:

the connection to the remote server timed out

瞬间欣喜若狂,既然有超时错误,必然有设置超时的接口吧!遗憾,遗憾,遗憾。。。重要的事情说 3遍,翻遍了官方文档,能和超时扯上关系的就这么一个简单的常量说明(当然还有QNetworkReply::ProxyTimeoutError)。

这种情况下,我们只能自己去处理超时了。

如何处理超时

解决思路:

  • 使用 QTimer 启动一个单次定时器,并设置超时时间。
  • 在事件循环退出之后,判断定时器的状态,如果是激活状态,证明请求已经完成;否则,说明超时。

来看一个简单的例子 - 获取 Qt 官网 网页内容:


QTimer timer;
timer.setInterval(30000); // 设置超时时间 30
timer.setSingleShot(true); // 单次触发
// 请求 Qt 官网


QNetworkAccessManager manager;


QNetworkRequest request;


request.setUrl(QUrl("http://qt-project.org"));


request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");


QNetworkReply *pReply = manager.get(request);


QEventLoop loop;


connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);


connect(pReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);


timer.start();


loop.exec();  

// 启动事件循环


if (timer.isActive())

 {  

    // 处理响应


  timer.stop();

  if (pReply->error() != QNetworkReply::NoError) {

  // 错误处理

  qDebug() << "Error String : " << pReply->errorString();

  } 

      else {

  QVariant variant = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute);

  int nStatusCode = variant.toInt();

  // 根据状态码做进一步数据处理
        //QByteArray bytes = pReply->readAll();

  qDebug() << "Status Code : " << nStatusCode;

  } 

} 

else {

 // 处理超时


disconnect(pReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    pReply->abort();
    pReply->deleteLater();


    qDebug() << "Timeout";


}

首先,定义一个 QTimer,设置超时时间为 30000 毫秒(30 秒)并设置为单次触发。然后,使用QNetworkRequest 实现一个简单的网络请求,通过 QNetworkAccessManager::get() 开始获取 Qt官网的 HTML 页面内容。因为请求过程是异步的,所以通过使用 QEventLoop 启动一个事件循环让其同步处理,并将 QTimer的 timeout() 信号以及 QNetworkReply 的 finished() 信号连接至其 quit()槽函数,保证在定时器过期之后或者网络响应完成后事件循环得到退出,不至于一直处于阻塞状态。

如上所述,事件循环退出的两种情况:

  • QTimer 30 秒到期,超时
  • 网络连接响应完成

所以,当 QTimer::isActive() 激活的情况下,证明响应完成,还尚未超时。这时需要先调用QTimer::stop() 来停止定时器,再对响做进一步处理。否则,进行超时处理 - QNetworkReply::abort()立即中止操作并关闭网络连接。

封装类

既然以后会经常用到,那么还是提供一个封装类 QReplyTimeout 专门处理超时。

 
  
#include "QObject"


#include "QTimer"


#include "QNetworkReply"


class QReplyTimeout : public QObject {


 Q_OBJECT


public:

  QReplyTimeout(QNetworkReply *reply, const int timeout) : QObject(reply) {

           Q_ASSERT(reply);

    if (reply && reply->isRunning()) {  // 启动单次定时器                                   QTimer::singleShot(timeout, this, SLOT(onTimeout()));

     }

  }


signals:

  void timeout();  // 超时信号 - 供进一步处理


private slots:

  void onTimeout() {

   // 处理超时

       QNetworkReply *reply = static_cast<<span style=" color:#800080;">QNetworkReply*>(parent());

  if (reply->isRunning()) {

    reply->abort();

    reply->deleteLater();

   emit timeout();

   }

  }


};

由于 QNetworkReply 和 QReplyTimeout 是父子关系,所以 QReplyTimeout将被自动销毁。

使用起来非常简单:

QNetworkAccessManager *pManger = new QNetworkAccessManager(this);


QNetworkReply *pReply = pManger->get(QNetworkRequest(QUrl("https://www.google.com")));
QReplyTimeout *pTimeout = new QReplyTimeout(pReply, 1000);


// 超时进一步处理


connect(pTimeout, &QReplyTimeout::timeout, [=]() {

 qDebug() << "Timeout";


});

如果对 Google 的获取未在 1000 毫秒(1 秒)内完成,则会中止,并发出 timeout()信号,供进一步处理(例如:提示用户请求超时)。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值