Qt 之处理QNetworkAccessManager请求超时处理

2024-06-20 07:48

本文主要是介绍Qt 之处理QNetworkAccessManager请求超时处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、QNetworkAccessManager相关信号
  • 二、超时处理
    • 1.超时原因(参考过来的)
    • 2.如何处理超时
    • 3.封装类
  • 总结


前言

项目中,需要用http,get post,去后端请求服务,而由于网络情况不定,在非常弱网的情况下,http长时间拿不到应答,所以项目需要自己手动做个计时,超过该时间主动放弃该请求。
qt中QNetworkAccessManager提供了非常方便的异步api,但是手动设置超时的相关接口,需要自己来实现。


提示:以下是本篇文章正文内容,下面案例可供参考

一、QNetworkAccessManager相关信号

QNetworkAccessManager * pManager = new QNetworkAccessManager(this);
QNetworkRequest request(url);
QNetworkReply *reply = pManager->get(request);
connect( reply , SIGNAL(uploadProgress(qint64,qint64)),this, SIGNAL(uploadProgress(qint64,qint64)) );
connect(reply , SIGNAL(downloadProgress(qint64,qint64)),SLOT(downloadProgress(qint64,qint64)));
connect(reply , SIGNAL(finished()),SLOT(downloadFinished()));
connect(reply , SIGNAL(readyRead()),SLOT(downloadReadyRead()));
connect(reply , SIGNAL(error(QNetworkReply::NetworkError)),SLOT(downloadError(QNetworkReply::NetworkError)));

downloadProgress,uploadProgress 用来监控当前下载或上传文件的进度
finished信号会在请求完成时发出
readyRead在下载过程中有数据到来时,可读出
error是当请求出错时发出

注意:本文中,超时处理会主动abort(); 调用abort()之后,会先发出error 然后发出 finished信号
导致error发出的原因有很多种,具体请看qt的帮助手册
在这里插入图片描述

二、超时处理

1.超时原因(参考过来的)

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

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

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

常量 QNetworkReply::TimeoutError:

the connection to the remote server timed out

2.如何处理超时

解决思路:
使用 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() 立即中止操作并关闭网络连接。

3.封装类

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

#include <QObject>
#include <QTimer>
#include <QNetworkReply>class QReplyTimeout : public QObject {Q_OBJECTpublic: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() 信号,供进一步处理(例如:提示用户请求超时)

总结

提示:自己对该封装类结合项目做了些修改

#ifndef QREPLYTIMER_H
#define QREPLYTIMER_H#include <QObject>
#include <QTimer>
#include <QNetworkReply>class QReplyTimeout : public QObject {Q_OBJECTpublic:QReplyTimeout(QNetworkReply *reply, const int timeout) : QObject(reply) {Q_ASSERT(reply);if (reply && reply->isRunning()) {  // 启动单次定时器timer.setInterval(timeout);timer.setSingleShot(true);connect(&timer,SIGNAL(timeout()),this,SLOT(onTimeout()));timer.start();//QTimer::singleShot(timeout, this, SLOT(onTimeout()));}}bool isTimerActive(){return  timer.isActive();}void stopTimer(){timer.stop();}
signals:void timeout();  // 超时信号 - 供进一步处理private slots:void onTimeout() {  // 处理超时QNetworkReply *reply = static_cast<QNetworkReply*>(parent());if (reply->isRunning()) {reply->abort();reply->deleteLater();emit timeout();}}private:QTimer timer;
};#endif // QREPLYTIMER_H

用法:


```cpp
QPointer<QNetworkReply > pNetworkResponse = m_pmanager->post(request,multiPart);
QReplyTimeout *pTimeout = new QReplyTimeout(pNetworkResponse, 10000);
// 超时进一步处理
connect(pTimeout, &QReplyTimeout::timeout, [=]() {qDebug() << "QReplyTimeout ";});
connect(pNetworkResponse, SIGNAL(error(QNetworkReply::NetworkError)),this, SLOT(httpError(QNetworkReply::NetworkError)));
QObject::connect(pNetworkResponse, &QNetworkReply::finished, [=]()mutable{file->close();delete file;file = NULL;//未超时if(pTimeout->isTimerActive()){pTimeout->stopTimer();}     
}

方式2:

connect(&m_networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
void MainWindow::replyFinished(QNetworkReply *reply)
{// 获取响应状态码,200表示正常// QVariant nCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);if (reply->error() == QNetworkReply::NoError){QByteArray bytes = reply->readAll();}else{// 错误处理-显示错误信息qDebug() <<  reply->error() ; //errorstring}
}

这篇关于Qt 之处理QNetworkAccessManager请求超时处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1077528

相关文章

百度OCR识别结构结构化处理视频

https://edu.csdn.net/course/detail/10506

如何在Java中处理JSON数据?

如何在Java中处理JSON数据? 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨在Java中如何处理JSON数据。JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,在现代应用程序中被广泛使用。Java通过多种库和API提供了处理JSON的能力,我们将深入了解其用法和最佳

axios全局封装AbortController取消重复请求

为什么? 问题:为什么axios要配置AbortController?防抖节流不行吗? 分析: 防抖节流本质上是用延时器来操作请求的。防抖是判断延时器是否存在,如果存在,清除延时器,重新开启一个延时器,只执行最后一次请求。节流呢,是判断延时器是否存在,如果存在,直接return掉,直到执行完这个延时器。事实上,这些体验感都不算友好,因为对于用户来说,得等一些时间,尤其是首次请求,不是那么流畅

AI学习指南机器学习篇-朴素贝叶斯处理连续特征和离散特征

AI学习指南机器学习篇-朴素贝叶斯处理连续特征和离散特征 在机器学习领域,朴素贝叶斯是一种常用的分类算法,它的简单性和高效性使得它在实际应用中得到了广泛的应用。然而,在使用朴素贝叶斯算法进行分类时,我们通常会面临一个重要的问题,就是如何处理连续特征和离散特征。因为朴素贝叶斯算法基于特征的条件独立性假设,所以对于不同类型的特征,我们需要采取不同的处理方式。 在本篇博客中,我们将探讨如何有效地处理

QT 中ListView和ListWidget有什么区别

ListView和ListWidget在Qt框架中都是用于显示列表数据的控件,但它们在使用方法和特性上存在一些明显的差异。以下是关于它们用法不一样的地方的详细分析: 数据管理方式: ListView:使用QAbstractItemModel数据模型来管理和显示列表数据。QAbstractItemModel是一个抽象类,允许开发者自定义数据模型以适应特定的数据结构和需求。这使得ListView在处

神经网络第四篇:推理处理之手写数字识别

到目前为止,我们已经介绍完了神经网络的基本结构,现在用一个图像识别示例对前面的知识作整体的总结。本专题知识点如下: MNIST数据集图像数据转图像神经网络的推理处理批处理  MNIST数据集          mnist数据图像 MNIST数据集由0到9的数字图像构成。像素取值在0到255之间。每个图像数据都相应地标有“7”、“2”、“1”等数字标签。MNIST数据集中,

vue怎么处理跨域

Vue.js 本身并不直接解决跨域问题,因为跨域问题主要是浏览器基于同源策略(Same-origin policy)的一种安全限制。然而,在Vue.js项目中,我们可以采取一些策略来绕过或处理跨域问题。 解决跨域问题的常用方法: 代理服务器:在开发环境中,我们可以配置一个代理服务器来转发API请求,从而绕过浏览器的同源策略。Vue CLI 提供了内置的代理功能,可以在 vue.config.j

【机器学习】自然语言处理的新前沿:GPT-4与Beyond

📝个人主页:哈__ 期待您的关注  目录 🔥引言 背景介绍 文章目的 一、GPT-4简介 GPT-4概述 主要特性 局限性和挑战 二、自监督学习的新进展 自监督学习的原理 代表性模型和技术 三、少样本学习和零样本学习 少样本学习的挑战 先进方法 四、跨模态学习 跨模态学习的概念 代表性技术 应用场景 第五部分:可解释性和透明性 AI的可解释

【文末附gpt升级秘笈】腾讯元宝AI搜索解析能力升级:千万字超长文处理的新里程碑

腾讯元宝AI搜索解析能力升级:千万字超长文处理的新里程碑 一、引言 随着人工智能技术的飞速发展,自然语言处理(NLP)和机器学习(ML)在各行各业的应用日益广泛。其中,AI搜索解析能力作为信息检索和知识抽取的核心技术,受到了广泛的关注和研究。腾讯作为互联网行业的领军企业,其在AI领域的探索和创新一直走在前列。近日,腾讯旗下的AI大模型应用——腾讯元宝,迎来了1.1.7版本的升级,新版本在AI搜

AndroidStudio打包处理

AndroidStudio非常强大,公司最近有一个需求是要实现对一个APP进行多个版本的打包,而且可以同时安装在手机上。这个需求详细一点的描述是:公司有一个APP,有多个开发商要使用我们的APP,为了大家都想有一个自己的APP,而且图标不一样,app名字不一样,背景不一样等。我查询了一下资料发现,在AndroidStudio的gradle是可以配置的。在此特意写一篇文章记录分享。 配置签名 首