Qt之处理QNetworkAccessManager网络连接超时

简述

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

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

  • 简述
  • 超时原因
  • Qt 中的网络连接超时
  • 如何处理超时
  • 封装类

超时原因

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

  • 网络断开,不过经常显示无法连接
  • 网络阻塞,导致你不能在程序默认等待时间内得到回复数据包
  • 网络不稳定,网络无法完整传送服务器信息
  • 系统问题,系统资源过低,无法为程序提供足够的资源处理服务器信息
  • 设备不稳定,如网线松动、接口没插好等等
  • 网络注册时系统繁忙,无法回应
  • 网速过慢,如 使用 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<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() 信号,供进一步处理(例如:提示用户请求超时)。

时间: 2024-09-20 08:52:30

Qt之处理QNetworkAccessManager网络连接超时的相关文章

Win8.1系统连接应用商店提示“网络连接超时”怎么办

  Win8.1系统连接应用商店提示"网络连接超时"怎么办?下面小编告诉大家解决方法. 解决方法: 1.手动设置DNS 右键网络连接图标,选择"打开网络和共享中心",点击现在连接的网络名称,打开网络状态窗口,点击"属性",在网络属性窗口中双击"Internet协议版本4,将DNS服务器手动设置为"4 2 2 2"和"4 2 2 1",确定后重试. 2.清理应用商店缓存 按下Win+R键输入&quo

centos-急急急!新手!PieTTY连centOS出现网络连接超时

问题描述 急急急!新手!PieTTY连centOS出现网络连接超时 From 192.168.8.100 icmp_seq=298 Destination Host Unreachable From 192.168.8.100 icmp_seq=300 Destination Host Unreachable From 192.168.8.100 icmp_seq=301 Destination Host Unreachable From 192.168.8.100 icmp_seq=302 D

动车上的书摘-java网络 连接服务器

一.服务器初试-telnet工具     当我们编写网络程序时,我们应该认识telnet的小工具(unix 和 win 自带).Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式.它为用户提供了在本地计算机上完成远程主机工作的能力.win自带的telnet要去开启,开启的步骤如下:                                   注意:第一:打开控制面板,打开程序和功能,看到左边有个"打开或关闭Windows功能 ,打开找到tel

使用C#调用外部Ping命令获取网络连接情况

网络 以前在玩Windows 98的时候,几台电脑连起来,需要测试网络连接是否正常,经常用的一个命令就是Ping.exe.感觉相当实用. 现在 .net为我们提供了强大的功能来调用外部工具,并通过重定向输入.输出获取执行结果,下面就用一个例子来说明调用Ping.exe命令实现网络的检测,希望对.net初学者有所帮助. 首先,我们用使用Process类,来创建独立的进程,导入System.Diagnostics, using System.Diagnostics; 实例一个Process类,启动一

连接超时-Connection timed out:

问题描述 Connection timed out: java.net.ConnectException: Connection timed out: connect java.net.PlainSocketImpl.socketConnect(Native Method) java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351) java.net.PlainSocketImpl.connectToAddress(PlainSock

java-socket连接超时,时好时坏的

问题描述 socket连接超时,时好时坏的 给移动做了个app,用手机号码登录报socket连接超时,这应该是移动那边的问题吧? 解决方案 时好时坏应该是网络的原因,你ping下看看延迟 解决方案二: 把超时设置的时限调大一些看看

ORA-12170:TNS:连接超时

在Red Hat Enterprise Linux Server Releae 5.5 成功安装ORACLE 10g 后,在客户端配置TNS后,测试是否可以连接到数据块服务器,结果报错: ORA-12170:TNS:连接超时 1:首先检查网络是否能ping通,如下所示,网络是畅通的.   2:检查TNS配置(TNS配置也没有问题) GSP =(DESCRIPTION =(ADDRESS =(PROTOCOL = TCP)(HOST = 172.20.36.79)(PORT = 1521))(CO

android 请求服务器间断性的连接超时,会是什么原因?

问题描述 android 请求服务器间断性的连接超时,会是什么原因? 问题是这样的, android 使用HTTP请求自己的服务器 会出现某段时间所有的请求都会超时, 然后只要有一次请求成功, 超时就都没了,所有接口都正常了. 我看不出android这边http请求的代码有什么问题, 就找了一个 获取天气的外部接口,用我们的代码调用,就从没出现超时问题.怀疑服务器端有问题, 但是ios端 用这些接口又没有问题.搞不懂什么状况了,会是什么原因导致的了? 解决方案 我猜测 你应该使用的移动网络吧 如

iOS下的实际网络连接状态检测:RealReachability

序言 网络连接状态检测对于我们的iOS app开发来说是一个非常通用的需求.为了更好的用户体验,我们会在无网络时展现本地或者缓存的内容,并对用户进行合适的提示.对绝大部分iOS开发者来说,从苹果示例代码改变而来的各种Reachablity框架是实现这个需求的普遍选择,比如这个库.但事实上,基于此方案的所有实现,都无法帮助我们检测真正的网络连接状态,它们能检测的只是本地连接状态:这种情况包括但不限于如下场景: 1.现在很流行的公用wifi,需要网页鉴权,鉴权之前无法上网,但本地连接已经建立: 2.