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

相关文章

Java堆转储文件之1.6G大文件处理完整指南

《Java堆转储文件之1.6G大文件处理完整指南》堆转储文件是优化、分析内存消耗的重要工具,:本文主要介绍Java堆转储文件之1.6G大文件处理的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言文件为什么这么大?如何处理这个文件?分析文件内容(推荐)删除文件(如果不需要)查看错误来源如何避

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

Java docx4j高效处理Word文档的实战指南

《Javadocx4j高效处理Word文档的实战指南》对于需要在Java应用程序中生成、修改或处理Word文档的开发者来说,docx4j是一个强大而专业的选择,下面我们就来看看docx4j的具体使用... 目录引言一、环境准备与基础配置1.1 Maven依赖配置1.2 初始化测试类二、增强版文档操作示例2.

MyBatis-Plus通用中等、大量数据分批查询和处理方法

《MyBatis-Plus通用中等、大量数据分批查询和处理方法》文章介绍MyBatis-Plus分页查询处理,通过函数式接口与Lambda表达式实现通用逻辑,方法抽象但功能强大,建议扩展分批处理及流式... 目录函数式接口获取分页数据接口数据处理接口通用逻辑工具类使用方法简单查询自定义查询方法总结函数式接口

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2

Python设置Cookie永不超时的详细指南

《Python设置Cookie永不超时的详细指南》Cookie是一种存储在用户浏览器中的小型数据片段,用于记录用户的登录状态、偏好设置等信息,下面小编就来和大家详细讲讲Python如何设置Cookie... 目录一、Cookie的作用与重要性二、Cookie过期的原因三、实现Cookie永不超时的方法(一)

Qt QCustomPlot库简介(最新推荐)

《QtQCustomPlot库简介(最新推荐)》QCustomPlot是一款基于Qt的高性能C++绘图库,专为二维数据可视化设计,它具有轻量级、实时处理百万级数据和多图层支持等特点,适用于科学计算、... 目录核心特性概览核心组件解析1.绘图核心 (QCustomPlot类)2.数据容器 (QCPDataC