Qt中的网络客户端

news2024/10/7 12:51:41

目录

HttpClient

http报文相关

HttpClient发送报文格式

x-www-form-urlencoded:

multipart/form-data

raw

binary

QUrl

QNetworkAccessManager

Http-Get

Http-Post

http-post:form-data

ftp-up

ftp-down

QDesktopServices


HttpClient

http报文相关

URL是为了 统一的命名网络中的一个资源(URL不是单单为了HTTP协议而定义的,而是网络上的所有的协议都可以使用) ;因此URL有以下特点:

  • URL是可移植的。(所有的网络协议都可以使用URL)

  • URL的完整性。(不能丢失数据,比如URL中包含二进制数据时,如何处理)

  • URL的可阅读性。(希望人能阅读)

    因为一些历史的原因URL设计者使用US-ASCII字符集表示URL。(原因比如ASCII比较简单;所有的系统都支持ASCII) 。

    http报文

    http报文是面向文本的,报文中每一个字段都是一些ASCII码串,各个字段的长度是不确定的 。http有两类报文:请求报文 响应报文 。

使用GET方法时,请求参数和对应的值附加在URL后面,利用一个问号("?")代表URL的结尾与请求参数的开始,传递参数长度受限制,例如: /index.jsp?id=100&op=bind 。

1.请求行

          请求行由请求方法字段、URL字段和HTT协议版本字段组成;空格隔开eg:GET /index.html HTTP/1.1

        HTTP请求的方法:GET POST HEAD PUT DELETE OTIONS TRACE CONNECT

       GET:一般客户端从server读取信息;请求参数和值附加在URL后面,?隔开。传递参数长度受限。eg:/etccharging?id=erdfwsaxnjdcdcd&secret=qw2dccbhcv;

        POST:可以传递更多的信息给服务器,将参数封装在HTTP请求数据中,可以传递大量数据,可用来传文件。

2.消息头部

        请求头部以键值对组成,一行一对,分号隔开,主要包含通知Server关于Client的请求信息;如:   

        User-Agent:产生请求的浏览浏览器类型;

        Accet:Client端可识别的内容列表

        Host:请求的主机名。

3.空行

        最后一个请求头之后是一个空行、发送回车符和换行符通知服务器请求头结束,是完整的Http报文必须格式(据此可以设计解析报文)。

4.请求正文

        请求数据不在GET方法中使用,一般POST中主要使用,通常设置与此相关头Content-Type 和Content-Length

HttpClient发送报文格式

multipart/form-data、x-www-form-urlencoded、raw、binary

x-www-form-urlencoded:

1,它是post的默认格式,使用URLencode转码方法。包括将name、value中的空格替换为加号;将非ascii字符做百分号编码;将input的name、value用‘=’连接,不同的input之间用‘&’连接 。

2、百分号编码:比如汉字‘武’吧,他的utf8编码在十六进制下是0xE69CA6,占3个字节,把它转成字符串‘E69CA6’,变成了六个字节,每两个字节前加上百分号前缀,得到字符串“%E6%9C%A6”,变成九个ascii字符,占九个字节。把这九个字节拼接到数据包里,这样就可以传输“非ascii字符的 utf8编码的 十六进制表示的 字符串的 百分号形式”

3,同样使用URLencode转码,这种post格式跟get的区别在于,get把转换、拼接完的字符串用‘?’直接与表单的action连接作为URL使用,所以请求体里没有数据;而post把转换、拼接后的字符串放在了请求体里 不会在浏览器的地址栏显示,稍微安全一些。

multipart/form-data

1、对于一段utf8编码的字节,用application/x-www-form-urlencoded传输其中的ascii字符没有问题,但对于非ascii字符传输效率就很低了(汉字‘武’从三字节变成了九字节),因此在传很长的字节(如文件)时应用multipart/form-data格式。smtp等协议也使用或借鉴了此格式。

2、此格式表面上发送一段一句话和一个文件,请求体如下

同时请求头里规定了Content-Type: multipart/form-data;

boundary=----WebKitFormBoundarymNhhHqUh0p0gfFa8

可见请求体里不同的input之间用一段叫boundary的字符串分割,每个input都有了自己一个小header,其后空行接着是数据。

multipart/form-data将表单中的每个input转为了一个由boundary分割的小格式,没有转码,直接将utf8字节拼接到请求体中(然后逐字节转码ASCII),在本地有多少字节实际就发送多少字节,极大提高了效率,适合传输长字节

raw

可以上传任意格式的文本,可以上传text、json、xml、html等。

binary

相当于Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。

QUrl

对字符串进行 URL 格式化编码 ;

[static] QByteArray QUrl::toPercentEncoding(const QString &input, const QByteArray &exclude = QByteArray(), const QByteArray &include = QByteArray())

Returns an encoded copy of input. input is first converted to UTF-8, and all ASCII-characters that are not in the unreserved group are percent encoded. To prevent characters from being percent encoded pass them to exclude. To force characters to be percent encoded pass them to include.

Unreserved is defined as: ALPHA / DIGIT / "-" / "." / "_" / "~"

  QByteArray ba = QUrl::toPercentEncoding("{a fishy string?}", "{}", "s");
  qDebug(ba.constData());
  // prints "{a fi%73hy %73tring%3F}"
遵循这些原则,以避免在处理 URL 和字符串时,出现错误的字符转换:当从一个 QByteArray 或一个char * 创建包含 URL 的 QString 时,记得要用 QString::fromUtf8()。

URL格式

scheme

scheme 指定使用的传输协议,它由 URL 起始部分的一个或多个 ASCII 字符表示。scheme 只能包含 ASCII 字符,对输入不做转换或解码,必须以 ASCII 字母开始。

scheme 严格兼容 RFC 3986:scheme = ALPHA *( ALPHA / DIGIT / “+” / “-” / “.” )

协议描述
file资源是本地计算机上的文件。格式:file:///,注意后边应是三个斜杠。
ftp通过 FTP 访问资源。格式:FTP://
gopher通过 Gopher 协议访问该资源。
http通过 HTTP 访问该资源。格式:HTTP://
https通过安全的 HTTPS 访问该资源。格式:HTTPS://
mailto资源为电子邮件地址,通过 SMTP 访问。格式:mailto:
MMS通过支持MMS(流媒体)协议的播放该资源(代表软件:Windows Media Player)。格式:MMS://
ed2k通过 支持ed2k(专用下载链接)协议的P2P软件访问该资源(代表软件:电驴)。格式:ed2k://
Flashget通过 支持Flashget:(专用下载链接)协议的P2P软件访问该资源(代表软件:快车)。格式: Flashget://
thunder通过 支持thunder(专用下载链接)协议的 P2P 软件访问该资源(代表软件:迅雷)。格式: thunder://
news通过 NNTP 访问该资源。

下图显示了一个 URL,其 scheme 是 ftp

这里写图片描述

要设置 scheme,使用以下方式:

QUrl url;url.setScheme("ftp");12

Authority

URL 的 authority 由用户信息、主机名和端口组成。所有这些元素都是可选的,即使 authority 为空,也是有效的。

格式:username:password@hostname:port

用户信息和主机由'@' 分割,主机和端口由 ':'分割 。如果用户信息为空,'@' 必须被省略。尽管端口为空时,允许使用 ':'

这里写图片描述

host:指存放资源的服务器的域名系统(DNS)主机名或 IP 地址。

port:整数,可选,省略时使用方案的默认端口,各种传输协议都有默认的端口号,如 HTTP 的默认端口为80。如果输入时省略,则使用默认端口号。有时候出于安全或其他考虑,可以在服务器上对端口进行重定义,即采用非标准端口号,此时,URL 中就不能省略端口号这一项。

user info

user info 指用户信息,是 URL 中 authority 可选的一部分。

用户信息包括:用户名和一个可选的密码,由 ':' 分割。 如果密码为空,':'必须被省略。

这里写图片描述

path

由零或多个 / 隔开的字符串,一般用来表示主机上的一个目录或文件地址。在 authority 之后,query 之前。

这里写图片描述

对于没有层级的 schemes,路径将是 scheme 后的所有部分,像下面这样:

这里写图片描述

query

query 指查询字符串,可选,用于给动态网页(例如:使用 CGI、ISAPI、PHP/JSP/ASP/ASP、.NET 等技术制作的网页)传递参数,可有多个参数,用 & 隔开,每个参数的名和值用 = 隔开。

这里写图片描述

fragment

fragment 指定网络资源中的片断。是 URL 的最后一部分,由'#' 后面跟的字符串表示。通常指的是用于 HTTP 页面上的某个链接或点。

例如:一个网页中有多个名词解释,可使用 fragment 直接定位到某一名词解释。

这里写图片描述

fragment 有时也被称为 URL“引用”。

传递一个 QString()(null 字符串)将取消 fragment 的设置。传递一个参数 QString(“”)(空而非 null 字符串)将 fragment 设置为一个空字符串(和原始 URL 一样,只有一个 "#")。

QNetworkAccessManager

Http-Get


QString QHttpClient::Get(const QString&url, const QMap<QString, QString>&queryItemMap, const QMap<QString, QString>&headerMap)
{
	QUrl GetUrl(url);
	QNetworkRequest requestInfo;

	if (queryItemMap.isEmpty())
	{
		QUrlQuery query;//添加问好后面的key = value参数

		QMap<QString, QString>::const_iterator iter = queryItemMap.constBegin();
		while (iter != queryItemMap.constEnd()) {
			query.addQueryItem(iter.key(), iter.value());
			++iter;
		}
		GetUrl.setQuery(query);
	}

	requestInfo.setUrl(GetUrl);
	if (!headerMap.isEmpty())
	{
		QMap<QString, QString>::const_iterator iter = headerMap.constBegin();
		while (iter != headerMap.constEnd()) {
			requestInfo.setRawHeader(iter.key().toUtf8(), iter.value().toUtf8());
			++iter;
		}
	}
    
	QNetworkAccessManager NetWorkManager;
	QTimer timer;
	timer.setInterval(3000);
	timer.setSingleShot(true);
	QEventLoop eventLoop;
	QNetworkReply *reply = NetWorkManager.get(requestInfo);
	connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
	connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);
	eventLoop.exec();
	//错误处理
	QString replyStr;
	if (reply->error() == QNetworkReply::NoError)
	{
		replyStr = reply->readAll();
	}
	else
	{
		reply->deleteLater();
		qDebug() << reply->errorString();
	
	}
	return replyStr;
}

Http-Post

QString QHttpClient::Post(const QString&url, const QString&Content, const QMap<QString, QString>&headerMap)
{
	QUrl PostUrl(url);
	if (!PostUrl.isValid())
	{
		return "";
	}
	QNetworkRequest requestInfo(PostUrl);
	if (!headerMap.isEmpty())
	{
		QMap<QString, QString>::const_iterator iter = headerMap.constBegin();
		while (iter != headerMap.constEnd()) {
			requestInfo.setRawHeader(iter.key().toUtf8(), iter.value().toUtf8());
			++iter;
		}
	}
	requestInfo.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

	QNetworkAccessManager NetWorkManager;
	QTimer timer;
	timer.setInterval(3000);
	timer.setSingleShot(true);
	QEventLoop eventLoop;
	QNetworkReply *reply = NetWorkManager.post(requestInfo, Content.toUtf8());
	connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
	connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);
	eventLoop.exec();

	QString replyStr;
	if (reply->error() == QNetworkReply::NoError)
	{
		replyStr = reply->readAll();
	}
	else
	{
		reply->deleteLater();

	}
	qDebug() << reply;

	return replyStr;

}

http-post:form-data

QFile file(picpath);
	if (!file.open(QIODevice::ReadOnly))
	{
		
		cLogger(LOG_MODULE_NAME)->error("file open {} failed", picpath);
		return;
	}
	QByteArray imageData = file.readAll();
	QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

	QHttpPart imagePart;
	imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
	imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\";filename=\"" + file.fileName() + "\""));
	imagePart.setBody(imageData);
	multiPart->append(imagePart);
	

	QUrl qurl(url);
	QNetworkRequest request(qurl);
	
	QNetworkAccessManager NetManager;
	QTimer timer;
	timer.setInterval(m_sendTimeOut);
	timer.setSingleShot(true);
	QEventLoop eventLoop;
	QNetworkReply *reply = NetManager.post(request, multiPart);
	multiPart->setParent(reply);
	connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
	connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);
	eventLoop.exec();
	
	if (reply->error() == QNetworkReply::NoError)
	{
		strReply = reply->readAll();
		cLogger(LOG_MODULE_NAME)->info("reply: {}", strReply);
	}
	else
	{
		cLogger(LOG_MODULE_NAME)->error("Request connection failed! {}", reply->errorString());
	}

	reply->deleteLater();

ftp-up

bool QHttpClient::UploadFtp(const QString&host, const int port, const QString&username, const QString&password, const QByteArray&Content, const QString&uploadFilepath, bool bVertrify)
{
	QUrl ftpUrl;
	ftpUrl.setScheme("ftp");
	ftpUrl.setHost(host);
	ftpUrl.setPort(port);
	if (bVertrify)
	{
		ftpUrl.setUserName(username);//匿名则不需要
		ftpUrl.setPassword(password);//匿名则不需要
	}
	ftpUrl.setPath(uploadFilepath);

	QNetworkRequest requestInfo;
	requestInfo.setUrl(ftpUrl);

	QNetworkAccessManager ftpWorkManager;
	QTimer timer;
	timer.setInterval(3000);
	timer.setSingleShot(true);
	QEventLoop eventLoop;
	QNetworkReply *reply = ftpWorkManager.put(requestInfo, Content);
	connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
	connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);
	eventLoop.exec();
	if (reply->error() == QNetworkReply::NoError)
	{
		return true;
	}
	else
	{
		reply->deleteLater();
		return false;
	}
}

ftp-down

bool QHttpClient::DownLoadFtp(const QString&host, const int port, const QString&username, const QString&password, QString&getContentStr, const QString&uploadFilepath, bool bVertrify)
{
	QUrl ftpUrl;
	ftpUrl.setScheme("ftp");
	ftpUrl.setHost(host);
	ftpUrl.setPort(port);
	if (bVertrify)
	{
		ftpUrl.setUserName(username);//匿名则不需要
		ftpUrl.setPassword(password);//匿名则不需要
	}
	ftpUrl.setPath(uploadFilepath);
	

	QNetworkRequest requestInfo;
	requestInfo.setUrl(ftpUrl);

	QNetworkAccessManager ftpWorkManager;
	QTimer timer;
	timer.setInterval(3000);
	timer.setSingleShot(true);
	QEventLoop eventLoop;
	QNetworkReply *reply = ftpWorkManager.get(requestInfo);
	connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
	connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit);
	eventLoop.exec();
	if (reply->error() == QNetworkReply::NoError)
	{
		getContentStr = reply->readAll();
		return true;
	}
	else
	{
		reply->deleteLater();
		return false;
	}

}

QDesktopServices

        主要用于与桌面环境交互,启用外部程序打开任意URL地址。Qt会根据传进来的url决定具体的操作。可以应用在软件打开本地的帮助文档、生成的excel数据表快捷打开等等,也可以打开在线的帮助引导网页等。

ConstantValueDescription
QUrl::TolerantMode0QUrl试图纠正一些常见的url错误,便于解析不完全符合标准的url。
QUrl::StrictMode1只接受有效的url,可以验证url的格式。

自定义openUrl行为

外部程序运行效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2194186.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人机协作:科技与人类智慧的融合

随着科技的飞速发展&#xff0c;越来越多的领域开始借助人工智能&#xff08;AI&#xff09;和自动化技术来提升工作效率。人机协作&#xff08;Human-Machine Collaboration&#xff09;这一概念逐渐成为现代技术进步的核心。它不仅改变了我们的工作方式&#xff0c;也在重新定…

【STL】stack模拟实现

stack模拟实现比较简单&#xff0c;就是直接调用deque的函数即可。 具体实现&#xff1a; #pragma once#include<deque> #include<iostream>using std::istream; using std::ostream; using std::endl; using std::cout;namespace zyy { //stack -> 后进先出t…

python log函数怎么用

log() 返回 x 的自然对数。 语法 以下是 log() 方法的语法&#xff1a; import math math.log(x[, base]) 注意&#xff1a;log()是不能直接访问的&#xff0c;需要导入 math 模块&#xff0c;通过静态对象调用该方法。 参数 x -- 数值表达式。 base -- 可选&#xff0c;底…

‌图片编辑为底片,智能工具助力,创作精彩视觉作品

在当今数字化时代&#xff0c;图像编辑已成为表达创意和美化视觉作品的重要手段。借助智能工具&#xff0c;即使是初学者也能轻松驾驭图片编辑。接下为大家展示图片编辑为底片图片的效果。 1.打开“首助编辑高手”&#xff0c;选择这里“图片批量处理”版块页面上 2.导入保存有…

C语言之三子棋游戏(附完整代码)

学了那么多关于C语言的知识&#xff0c;也该进行一下实操了。三子棋游戏应该是大家学生时代课间比较喜欢娱乐消遣的一种方式吧。那么我们今天就来说说如何实现简单版本的三子棋对战小游戏吧。 三子棋游戏介绍 三子棋游戏类似于五子棋&#xff0c;不同的是它的棋盘大小是九宫格…

LLM | Ollama 安装、运行大模型(CPU 实操版)

1. 操作步骤 1.1 安装 # 通过 homebrew 安装 brew install ollama1.2 验证&#xff08;可跳过&#xff09; # 输出命令使用提示则安装成功 ollama --help1.3 启动服务端 # 启动 ollama 服务&#xff08;默认在 11434 端口&#xff0c;模型文件在 ~/.ollama&#xff09; oll…

论文阅读笔记-Pre-trained Models for Natural Language Processing: A Survey

前言 预训练模型给下游任务带来的效果不言而喻,有了预训练模型,我们可以使用它来加速解决问题的过程。正如论文中所说的那样,预训练模型(PTMs)的出现将自然语言处理(NLP)带入了一个新时代。本篇论文基于分类从四个角度对现有PTMs进行系统分类,描述如何使PTMs的知识适应…

Spring源码学习:SpringMVC(4)DispatcherServlet请求入口分析

目录 前言HttpServlet &FrameworkServletHttpServlet #serviceFrameworkServlet#processRequest DispatcherServlet#doServicedoDispatchcheckMultipartgetHandlerAbstractHandlerMapping#getHandlerRequestMappingInfoHandlerMapping#getHandlerInternalAbstractHandlerMe…

Excel-查找和引用数据-VLOOKUP 和 HLOOKUP 函数

在 Excel 中&#xff0c;VLOOKUP 和 HLOOKUP 是用于查找和引用数据的函数。下面是它们的基本用法&#xff1a; VLOOKUP 用途&#xff1a;在表格的第一列中查找某个值&#xff0c;并返回该值所在行的指定列中的数据。 语法&#xff1a; VLOOKUP(lookup_value, table_array, …

多模态大语言模型(MLLM)-Blip2深度解读

前言 Blip2是一个多模态大语言模型&#xff0c;因其提出时间较早&#xff08;2023年&#xff09;&#xff0c;且效果较好&#xff0c;很快成为一个标杆性工作。Blip2中提出的Q-former也成为衔接多模态和文本的重要桥梁。 Blip2发表时间是2023年&#xff0c;现在引用已经3288了…

产品经理内容分享(一):AI产品经理需必备那些能力

目录 必备的AI技术知识 第一章&#xff1a;AI产品经理是否需要懂技术及其程度 第二章&#xff1a;AI产品经理必备的AI技术基础知识——基础算法与机器学习方法 第三章&#xff1a;AI产品经理必须要懂的AI技术知识——场景应用 第四章&#xff1a;AI算法与模型的关系 第五…

PhotoMaker部署文档

一、介绍 PhotoMaker&#xff1a;一种高效的、个性化的文本转图像生成方法&#xff0c;能通过堆叠 ID 嵌入自定义逼真的人类照片。相当于把一张人的照片特征提取出来&#xff0c;然后可以生成你想要的不同风格照片&#xff0c;如写真等等。 主要特点&#xff1a; 在几秒钟内…

求1000以内的完数

题目&#xff1a;一个数如果恰好等于他的因子之和&#xff08;包括1&#xff0c;但不包括这个数&#xff09;&#xff0c;这个数就是完数。编写算法找出1000之内的所有完数&#xff0c;并按下面格式输出其因子&#xff1a;28 its factors are 1,2,4,7,14 代码如下&#xff1a;…

Dell服务器电源配置

Dell服务器电源配置规则 PowerEdge 电源设置

医院综合服务系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;患者管理&#xff0c;医生管理&#xff0c;就诊信息管理&#xff0c;科室信息管理&#xff0c;挂号信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;订单排队&#…

《PyTorch深度学习快速入门教程》学习笔记(第15周)

目录 摘要 Abstract 1. 安装Anaconda 2. 查看显卡驱动 3. 安装Pytorch 4. Pytorch加载数据 5. 常用数据集两种形式 6. 路径直接加载数据 7. Dataset加载数据 摘要 本周报的目的在于汇报《PyTorch深度学习快速入门教程》课程第一周的学习成果&#xff0c;主要聚焦于py…

微服务Sleuth解析部署使用全流程

目录 1、Sleuth链路追踪 1、添加依赖 2、修改日志配置文件 3、测试 2、zipkin可视化界面 1、docker安装 2、添加依赖 3、修改配置文件 4、查看页面 5、ribbon配置 1、Sleuth链路追踪 sleuth是链路追踪框架&#xff0c;用于在微服务架构下开发&#xff0c;各个微服务之…

轻松部署大模型:Titan Takeoff入门指南

轻松部署大模型&#xff1a;Titan Takeoff入门指南 在人工智能的快速发展中&#xff0c;处理自然语言处理&#xff08;NLP&#xff09;任务的大规模语言模型&#xff08;LLM&#xff09;至关重要。然而&#xff0c;部署这些模型往往具有挑战性&#xff0c;需要高性能的硬件和优…

设计模式之适配器模式(Adapter)

一、适配器模式介绍 适配器模式(adapter pattern )的原始定义是&#xff1a;将类的接口转换为客户期望的另一个接口&#xff0c; 适配器可以让不兼容的两个类一起协同工作。 适配器模式是用来做适配&#xff0c;它将不兼容的接口转换为可兼容的接口&#xff0c;让原本由于接口…

YOLOv10改进,YOLOv10添加CA注意力机制,二次创新C2f结构,助力涨点

改进前训练结果: 二次创新C2f结构训练结果: 摘要 在本文中,提出了一种新的移动网络注意力机制,将位置信息嵌入到信道注意力中称之为“协调注意力”。与渠道关注不同通过 2D 全局池将特征张量转换为单个特征向量,坐标注意力因子将通道注意力转化为两个 1D 特征编码过程…