【QT HTTP】使用QtNetwork模块制作基于HTTP请求的C/S架构
目录
- 0 引言
- 1 HTTP基本知识
- 1.1 请求类型
- 1.2 HTTP请求报文格式
- 1.3 HTTP响应报文格式
- 1.4 拓展:GET vs POST 请求方法
- GET请求
- 请求报文:
- 响应报文
- POST请求
- 请求报文
- 响应报文
- 其他注意事项
- 示例:
- GET请求示例
- POST请求示例
- 2 实战
- 2.1 QtNetwork模块介绍
- 2.2 编程实现HTTP客户端
- 2.3 编程实现HTTP服务器

- 🙋♂️ 作者:海码007
- 📜 专栏:C++专栏
- 💥 标题:【QT HTTP】使用QtNetwork模块制作基于HTTP请求的C/S架构
- ❣️ 寄语:书到用时方恨少,事非经过不知难。
- 🎈 最后:文章作者技术和水平有限,如果文中出现错误,希望大家能指正!
0 引言
- 最近项目涉及到网络HTTP相关内容,需要处理客户端发送的POST、GET等请求。所以本文使用QT的QtNetwork模块来实现一个简单的发送POST、GET请求的客户端,然后响应POST、GET请求的服务器。
- 本文涉及到一些HTTP的基本知识,可以参考博主之前的文章:计算机网络HTTP协议
1 HTTP基本知识
1.1 请求类型
HTTP(Hypertext Transfer Protocol)协议 定义了多种请求方法,也称为HTTP请求类型或HTTP动词。这些请求方法表示客户端希望对特定资源执行的操作。以下是常见的HTTP请求类型、其功能和应用场景:
-
GET:
- 功能: 用于从服务器获取指定资源的信息。请求的参数通常附在URL后面,通过查询字符串传递。
- 应用场景: 用于查看网页、下载文件、获取数据等。是幂等的,不应该对服务器产生影响。(我们输入一个网址,其实就是从服务器获得一个HTML文件,然后浏览器内核再根据其将内容绘制出来)
-
POST:
- 功能: 用于向服务器提交数据,通常用于表单提交。请求的参数通常包含在请求体中。
- 应用场景: 用于创建新资源、提交表单数据、上传文件等。可能对服务器产生影响。不是幂等的,多次相同的POST请求可能产生不同的结果。
-
PUT:
- 功能: 用于向服务器上传新资源,或者更新已存在的资源。请求的参数通常包含在请求体中。
- 应用场景: 用于创建或更新资源。是幂等的,多次相同的PUT请求应该产生相同的结果。
-
DELETE:
- 功能: 用于请求服务器删除指定的资源。
- 应用场景: 用于删除指定资源。是幂等的,多次相同的DELETE请求应该产生相同的结果。
-
PATCH:
- 功能: 用于对资源进行部分更新。请求的参数通常包含在请求体中,表示对资源的局部修改。
- 应用场景: 用于对资源进行局部更新,而不是替换整个资源。
-
HEAD:
- 功能: 类似于GET请求,但服务器只返回响应头,不返回实体主体。常用于检查资源的元信息,如是否存在、是否已经修改等。
- 应用场景: 用于获取资源的头部信息,而不需要获取整个资源的内容。
-
OPTIONS:
- 功能: 用于获取目标资源支持的通信选项。客户端可以通过这个方法了解服务器支持的方法。
- 应用场景: 用于确定服务器支持的方法,以及支持的头信息等。
-
TRACE:
- 功能: 用于在目标服务器上执行一个消息环回测试,客户端发送的请求会在最终的服务器上返回,用于诊断和调试。
- 应用场景: 主要用于网络诊断,通常不会在实际应用中直接使用。
选择适当的HTTP请求类型取决于具体的操作和业务需求。每种请求类型都有其独特的功能和应用场景,使其适用于不同的情境。
1.2 HTTP请求报文格式
HTTP请求报文是客户端发送给服务器的文本信息,包含请求的各种参数和头信息。它的基本格式如下:
<Method> <Request-URI> <HTTP-Version>
<Headers><Optional Request Body>
其中,各部分的含义如下:
<Method>:HTTP请求方法,例如GET、POST、PUT等。<Request-URI>:请求的资源标识符,通常是一个URL。<HTTP-Version>:使用的HTTP协议版本,例如HTTP/1.1。<Headers>:包含多行的头部信息,每行都包含一个头字段和对应的值。<Optional Request Body>:可选的请求体,用于包含请求时需要发送的数据,例如POST请求中的表单数据。
以下是一个具体的例子:
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
Upgrade-Insecure-Requests: 1
在这个例子中:
- 请求方法是GET。
- 请求的资源标识符是
/index.html。 - 使用的HTTP协议版本是HTTP/1.1。
- 请求头部包含了
Host、User-Agent、Accept等字段,每个字段都以<header-name>: <header-value>的形式呈现。 - 由于GET请求通常不包含请求体,因此没有
<Optional Request Body>部分。
对于包含请求体的请求,例如POST请求,请求体会紧随请求头部,并用一个空行分隔。例如:
POST /submit-form HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 23username=johndoe&password=123
在这个例子中,请求体包含了表单数据username=johndoe&password=123,并通过Content-Type头字段指定了数据的格式。
1.3 HTTP响应报文格式
HTTP响应报文是服务器返回给客户端的文本信息,包含了服务器对客户端请求的响应。其基本格式如下:
<HTTP-Version> <Status-Code> <Reason-Phrase>
<Headers><Optional Response Body>
其中,各部分的含义如下:
<HTTP-Version>:使用的HTTP协议版本,例如HTTP/1.1。<Status-Code>:一个三位数的状态码,表示服务器对请求的处理结果。<Reason-Phrase>:状态码的文本描述,描述了状态码的原因。<Headers>:包含多行的头部信息,每行都包含一个头字段和对应的值。<Optional Response Body>:可选的响应体,用于包含服务器返回给客户端的数据。
以下是一个具体的例子:
HTTP/1.1 200 OK
Date: Mon, 15 Nov 2023 12:00:00 GMT
Server: Apache
Content-Type: text/html
Content-Length: 1234
Connection: keep-alive<html><head><title>Hello, World!</title></head><body><h1>Welcome to my website!</h1></body>
</html>
在这个例子中:
- 使用的HTTP协议版本是HTTP/1.1。
- 状态码是200,表示请求成功。
- 原因短语是"OK",为状态码的文本描述。
- 响应头部包含了
Date、Server、Content-Type等字段。 - 由于这是一个简单的HTML响应,响应体包含了一个HTML文档。
对于包含响应体的响应,例如HTML页面、JSON数据等,响应体会紧随响应头部,并用一个空行分隔。响应体的格式和内容取决于服务器的实际响应。
1.4 拓展:GET vs POST 请求方法
GET和POST请求在HTTP中的请求报文和响应报文中有一些区别,这主要涉及到数据的传递方式和一些特定的语义约定。
GET请求
请求报文:
- 参数传递: GET请求的参数通常附在URL的查询字符串中,通过
?和&符号进行连接,例如:http://example.com/resource?param1=value1¶m2=value2。 - 请求体: GET请求通常没有请求体,因为它用于请求资源,而不是向服务器提交数据。
响应报文
- 响应体: GET请求的响应体包含了服务器返回的资源数据。
POST请求
请求报文
- 参数传递: POST请求的参数通常包含在请求体中,而不是在URL中,特别是用于提交表单数据或上传文件等场景。
- 请求体: POST请求的请求体包含了客户端提交给服务器的数据。
响应报文
- 响应体: POST请求的响应体包含了服务器对提交的数据的处理结果。
其他注意事项
- 安全性: POST请求的数据包含在请求体中,相对于GET请求,POST请求具有更好的安全性,因为它不会在URL中明文传递敏感信息。
- 幂等性: GET请求是幂等的,多次相同的GET请求应该产生相同的结果。POST请求是非幂等的,多次相同的POST请求可能会产生不同的结果。
示例:
GET请求示例
请求报文:
GET /resource?param1=value1¶m2=value2 HTTP/1.1
Host: example.com
响应报文:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234<!DOCTYPE html>
<html><head><title>GET Response</title></head><body><h1>This is the response to a GET request.</h1></body>
</html>
POST请求示例
请求报文:
POST /submit-form HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 27param1=value1¶m2=value2
响应报文:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 45{"status": "success", "message": "POST response"}
总的来说,GET和POST请求的区别主要在于参数传递的方式、请求体的内容和请求的语义。GET适用于获取资源,而POST适用于向服务器提交数据。
2 实战
2.1 QtNetwork模块介绍
QtNetwork模块是Qt中用于网络编程的模块,提供了一系列用于处理网络通信的类和工具。以下是QtNetwork模块的一些主要功能:
-
TCP和UDP通信: 提供
QTcpSocket和QUdpSocket等类,用于实现TCP和UDP协议的通信。这些类使得在Qt应用程序中创建和管理网络连接变得相对简单。 -
HTTP客户端和服务器: 提供
QNetworkAccessManager类,用于实现HTTP协议的客户端功能。它支持GET、POST等HTTP请求方法,并允许异步地发送和接收HTTP请求。 -
网络请求和响应处理: 提供
QNetworkRequest和QNetworkReply等类,用于构建和处理网络请求。这些类提供了丰富的功能,包括请求头的设置、数据的传输和响应的处理等。 -
FTP客户端: 提供
QFtp类,用于实现FTP协议的客户端功能。它允许在Qt应用程序中进行文件传输操作。 -
网络代理: 支持网络代理设置,可以通过
QNetworkProxy类配置网络代理,以便在需要时通过代理服务器进行网络通信。 -
网络协议支持: QtNetwork模块支持各种网络协议,包括IPv4和IPv6,SSL/TLS等。这使得Qt应用程序能够适应多种网络环境和安全需求。
-
网络状态监控: 提供
QNetworkConfiguration和QNetworkConfigurationManager类,用于监控和管理网络配置,以便在应用程序中适应不同的网络状态。 -
网络缓存: 提供
QNetworkDiskCache等类,用于实现网络缓存,以提高应用程序的性能并减少对网络资源的依赖。
这些功能使QtNetwork成为一个强大的网络编程工具,适用于开发涉及网络通信的各种应用,从简单的客户端到复杂的服务器应用。
2.2 编程实现HTTP客户端
根据上述描述,可以知道,使用 QTcpSocket和QUdpSocket、QNetworkAccessManager、QNetworkRequest和QNetworkReply等类可以实现简单的HTTP客户端。
接下来是代码:
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QDebug>
#include <QUrlQuery>int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);// 创建网络访问管理器QNetworkAccessManager manager;// 创建HTTP请求QNetworkRequest getRequest(QUrl("http://example.com"));// 发送GET请求QNetworkReply *getReply = manager.get(getRequest);// 处理GET请求完成的信号QObject::connect(getReply, &QNetworkReply::finished, [&]() {if (getReply->error() == QNetworkReply::NoError) {qDebug() << "GET Response:" << getReply->readAll();} else {qDebug() << "GET Error:" << getReply->errorString();}getReply->deleteLater();});// 进入应用程序事件循环return a.exec();
}
在使用 Qt 进行网络请求时,尤其是在进行异步的网络操作时,需要进入应用程序的事件循环。这是因为 Qt 的事件循环负责处理事件,而网络请求的完成(比如接收到服务器的响应)通常是通过 Qt 的信号-槽机制来处理的。
让我们来详细解释一下:
-
异步操作: Qt 的网络操作通常是异步的,即在发起网络请求后,程序会继续执行后续的代码而不等待请求完成。这是为了确保应用程序的界面和其他部分能够保持响应性,不被阻塞。
-
信号-槽机制: 当网络请求完成时,
QNetworkReply会发出finished信号。你在代码中使用QObject::connect来连接这个信号到一个槽函数,以便在请求完成时执行一些操作。 -
事件循环: 为了让信号-槽机制正常工作,需要进入应用程序的事件循环。调用
QCoreApplication::exec()或者QEventLoop::exec()启动事件循环,使得 Qt 可以不断地检查并处理事件队列。
在代码中,调用 return a.exec(); 启动了事件循环。这样,当 GET 请求完成并发出 finished 信号时,相关的槽函数将会被执行。如果没有进入事件循环,这个槽函数将不会被触发,因为事件循环负责调度信号的处理。
简而言之,进入应用程序的事件循环是确保异步操作和信号-槽机制正常工作的关键步骤。如果你的应用程序没有事件循环,它将无法及时响应和处理异步操作的完成事件。
2.3 编程实现HTTP服务器
#ifndef MYHTTPSERVER_H
#define MYHTTPSERVER_H#include <QTcpServer>
#include <QTcpSocket>
#include <QUrlQuery>
#include <QDebug>class MyHTTPServer : public QTcpServer
{Q_OBJECTpublic:MyHTTPServer(QObject *parent = nullptr) : QTcpServer(parent) {}protected://--------------------------------------// 说明:这是 QTcpServer 类的虚函数,当有新的连接到达时,会被调用。// 日期:2023-11-15// 作者:何浩文//--------------------------------------void incomingConnection(qintptr socketDescriptor) override{QTcpSocket *socket = new QTcpSocket(this);socket->setSocketDescriptor(socketDescriptor);// 读取客户端请求connect(socket, &QTcpSocket::readyRead, [&]() {QByteArray requestData = socket->readAll();processRequest(requestData, socket);// 关闭连接socket->disconnectFromHost();});// 处理连接断开connect(socket, &QTcpSocket::disconnected, [&]() {socket->deleteLater();});}private://--------------------------------------// 说明:这个函数用于解析 HTTP 请求,分析请求的方法和路径,并调用相应的处理函数。// 日期:2023-11-15// 作者:海码007//--------------------------------------void processRequest(const QByteArray &requestData, QTcpSocket *socket){// 解析请求QString requestString = QString::fromUtf8(requestData);QStringList requestLines = requestString.split("\r\n");// 解析第一行,获取请求方法和路径QString firstLine = requestLines.first();QStringList parts = firstLine.split(" ");QString method = parts.value(0);QString path = parts.value(1);// 处理 GET 请求if (method == "GET"){handleGetRequest(path, socket);}// 处理 POST 请求else if (method == "POST"){handlePostRequest(path, requestData, socket);}}//--------------------------------------// 说明:处理 HTTP GET 请求的具体逻辑。// 日期:2023-11-15// 作者:海码007//--------------------------------------void handleGetRequest(const QString &path, QTcpSocket *socket){QTextStream responseStream(socket);responseStream.setAutoDetectUnicode(true);// 构造HTTP响应responseStream << "HTTP/1.1 200 OK\r\n"<< "Content-Type: text/html\r\n"<< "Connection: close\r\n"<< "\r\n"<< "<html><body><h1>Hello, World! (GET)</h1></body></html>";// 刷新并等待数据发送完毕socket->flush();socket->waitForBytesWritten();}//--------------------------------------// 说明:处理 HTTP POST 请求的具体逻辑。// 日期:2023-11-15// 作者:海码007//--------------------------------------void handlePostRequest(const QString &path, const QByteArray &requestData, QTcpSocket *socket){// 解析 POST 数据QUrlQuery postData(requestData);QString value = postData.queryItemValue("key");QTextStream responseStream(socket);responseStream.setAutoDetectUnicode(true);// 构造HTTP响应responseStream << "HTTP/1.1 200 OK\r\n"<< "Content-Type: text/html\r\n"<< "Connection: close\r\n"<< "\r\n"<< "<html><body><h1>Hello, " << value << "! (POST)</h1></body></html>";// 刷新并等待数据发送完毕socket->flush();socket->waitForBytesWritten();}
};#endif // MYHTTPSERVER_H
相关文章:
【QT HTTP】使用QtNetwork模块制作基于HTTP请求的C/S架构
目录 0 引言1 HTTP基本知识1.1 请求类型1.2 HTTP请求报文格式1.3 HTTP响应报文格式1.4 拓展:GET vs POST 请求方法GET请求请求报文:响应报文 POST请求请求报文响应报文 其他注意事项示例:GET请求示例POST请求示例 2 实战2.1 QtNetwork模块介绍…...
R语言绘制精美图形 | 火山图 | 学习笔记
一边学习,一边总结,一边分享! 教程图形 前言 最近的事情较多,教程更新实在是跟不上,主要原因是自己没有太多时间来学习和整理相关的内容。一般在下半年基本都是非常忙,所有一个人的精力和时间有限&#x…...
远程创建分支本地VScode看不到分支
在代码存放处右击,点击Git Bash Here 输入git fetch–从远程仓库中获取最新的分支代码和提交历史 就OK啦,现在分支可以正常查看了...
python后台框架简介
python后台框架 Python是一种流行的编程语言,它有许多优点,如简洁、易读、灵活和功能强大。Python也是一种常用的后端开发语言,它可以用来构建各种类型的网站和应用程序。Python有许多后端框架,可以帮助开发者快速地开发和部署后…...
spring boot validation使用
spring-boot-starter-validation 是 Spring Boot 中用于支持数据验证的模块。它建立在 Java Validation API(JSR-380)之上,提供了一种方便的方式来验证应用程序中的数据。以下是使用 spring-boot-starter-validation 的基本方法: …...
Hadoop3.3.4分布式安装
安装前提:已经配置好java环境,所有机器之间ssh的免密登录。 注意:下文中的flinkv1、flinkv2、flinkv3是三台服务器的别名 1.集群部署规划 注意:NameNode和SecondaryNameNode不要安装在同一台服务器 注意:ResourceMan…...
SQL ALTER TABLE 语句||SQL AUTO INCREMENT 字段
SQL ALTER TABLE 语句 ALTER TABLE 语句 ALTER TABLE 语句用于在现有表中添加、删除或修改列。 SQL ALTER TABLE 语法 若要向表中添加列,请使用以下语法: ALTER TABLE table_name ADD column_name datatype 若要删除表中的列&am…...
【源码系列】短剧系统开发国际版短剧系统软件平台介绍
系统介绍 短剧是一种快节奏、紧凑、有趣的戏剧形式,通过短时间的精彩表演,向观众传递故事的情感和思考。它以其独特的形式和魅力,吸引着观众的关注,成为了当代戏剧娱乐中不可或缺的一部分。短剧每一集都是一个小故事,…...
JavaWeb[总结]
文章目录 一、Tomcat1. BS 与 CS 开发介绍1.1 BS 开发1.2 CS 开发 2. 浏览器访问 web 服务过程详解(面试题)2.1 回到前面的 JavaWeb 开发技术栈图2.2 浏览器访问 web 服务器文件的 UML时序图(过程) ! 二、动态 WEB 开发核心-Servlet1. 为什么会出现 Servlet2. 什么是…...
如何解决小程序异步请求问题
小程序异步请求问题指的是在小程序中进行异步请求时可能会出现的问题,比如请求失败、请求超时等。以下是一些解决方案: 检查网络连接:首先需要确保网络连接正常,只有网络连接正常时才能正常进行异步请求。 检查请求参数ÿ…...
NSSCTF第12页(3)
[NSSCTF 2nd]php签到 首先,代码定义了一个名为 waf 的函数,用于执行一个简单的文件扩展名检查来防止上传恶意文件。 $black_list 是一个存储不允许的文件扩展名的数组,如 “ph”、“htaccess” 和 “ini”。 pathinfo($filename, PATHINF…...
基于ssm+vue交通事故档案系统
摘要 摘要是对文章、论文或其他文本的主要观点、结论和关键信息的简洁概括。由于你没有提供具体的文章或主题,我将为你创建一个通用的摘要。 本文介绍了一种基于SSM(Spring Spring MVC MyBatis)和Vue.js的交通事故档案管理系统的设计与实现…...
DNS1(Bind软件)
名词解释 1、DNS(Domain Name System) DNS即域名系统,它是一个分层的分布式数据库,存储着IP地址与主机名的映射 2、域和域名 域为一个标签,而有多个标签域构成的称为域名。例如hostname.example.com,其…...
PDF自动打印
最近接到用户提过来的需求,需要一个能够自动打印图纸的功能,经过几天的研究整出来个初版了的,分享出来给大家,希望能有帮助。 需求描述: 生产车间现场每天都有大量的图纸需要打印,一个一个打印太慢了࿰…...
【C#】类型转换-显式转换:括号强转、Parse法、Convert法、其他类型转string
目录 一、括号强转 1.有符号整型 2.无符号整型 3.浮点之间 4.无符号和有符号 5.浮点和整型 6.char和数值类型 7.bool和string是不能够通过 括号强转的 二、Parse法 1.有符号 2.无符号 3.浮点型 4.特殊类型 三、Convert法 1.转字符串 2.转浮点型 3.特殊类型转换…...
【智能家居】4、智能家居框架设计和代码文件工程建立
目录 一、智能家居项目框架 二、智能家居工厂模式示意 三、代码文件工程建立 SourceInsight创建新工程步骤 一、智能家居项目框架 二、智能家居工厂模式示意 三、代码文件工程建立 创建一个名为si的文件夹用于保存SourceInsight生成的文件信息,然后在SourceInsig…...
【GAN】数据增强基础知识
最近要用到,但是一点基础都没有,故开个文章记录一下笔记 目录 GAN DCGAN WGAN EEGGAN GAN 参考 生成对抗网络(GAN) - 知乎 (zhihu.com) 文章 [1406.2661] Generative Adversarial Networks (arxiv.org) 代码 GitHub - …...
Skywalking流程分析_3(服务的准备、启动、关闭)
前文将SkyWalkingAgent.premain中的: SnifferConfigInitializer.initializeCoreConfig(agentArgs)pluginFinder new PluginFinder(new PluginBootstrap().loadPlugins())这两个方法分析完毕,下面继续分析premain方法其余部分 创建byteBuddy final By…...
mysql中的各种日志文件redo log、undo log和binlog
mysql中的各种日志文件redo log、undo log和binlog mysql中的各种日志文件redo log、undo log和binlog1.MySQL日志文件类型2.redo log日志2.1 作用2.2工作原理:2.3详解 3.undo log日志4.binlog日志5.总结 mysql中的各种日志文件redo log、undo log和binlog 1.MySQL…...
【电视剧-长相思】经典语录
小编看了这么长时间的电视剧,突然感觉摘抄经典语录最有成就感,嘿嘿,下面是我在《长相思》(第一季)中感觉好的一些语录,语录是乱序排列哈 玟小六:我怕寂寞,寻不到长久的相依ÿ…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
