当前位置: 首页 > news >正文

C++ Web 编程

什么是 CGI?

  • 公共网关接口(CGI),是一套标准,定义了信息是如何在 Web 服务器和客户端脚本之间进行交换的。
  • CGI 规范目前是由 NCSA 维护的,NCSA 定义 CGI 如下:
  • 公共网关接口(CGI),是一种用于外部网关程序与信息服务器(如 HTTP 服务器)对接的接口标准。
  • 目前的版本是 CGI/1.1,CGI/1.2 版本正在推进中。

Web 浏览

为了更好地了解 CGI 的概念,让我们点击一个超链接,浏览一个特定的网页或 URL,看看会发生什么。

  • 您的浏览器联系上 HTTP Web 服务器,并请求 URL,即文件名。
  • Web 服务器将解析 URL,并查找文件名。如果找到请求的文件,Web 服务器会把文件发送回浏览器,否则发送一条错误消息,表明您请求了一个错误的文件。
  • Web 浏览器从 Web 服务器获取响应,并根据接收到的响应来显示文件或错误消息。

然而,以这种方式搭建起来的 HTTP 服务器,不管何时请求目录中的某个文件,HTTP 服务器发送回来的不是该文件,而是以程序形式执行,并把执行产生的输出发送回浏览器显示出来。

公共网关接口(CGI),是使得应用程序(称为 CGI 程序或 CGI 脚本)能够与 Web 服务器以及客户端进行交互的标准协议。这些 CGI 程序可以用 Python、PERL、Shell、C 或 C++ 等进行编写。

CGI 架构图

下图演示了 CGI 的架构:
在这里插入图片描述

Web 服务器配置

在您进行 CGI 编程之前,请确保您的 Web 服务器支持 CGI,并已配置成可以处理 CGI 程序。所有由 HTTP 服务器执行的 CGI 程序,都必须在预配置的目录中。该目录称为 CGI 目录,按照惯例命名为 /var/www/cgi-bin。虽然 CGI 文件是 C++ 可执行文件,但是按照惯例它的扩展名是 .cgi。

默认情况下,Apache Web 服务器会配置在 /var/www/cgi-bin 中运行 CGI 程序。如果您想指定其他目录来运行 CGI 脚本,您可以在 httpd.conf 文件中修改以下部分:

<Directory "/var/www/cgi-bin">AllowOverride NoneOptions ExecCGIOrder allow,denyAllow from all
</Directory><Directory "/var/www/cgi-bin">
Options All
</Directory>

在这里,我们假设已经配置好 Web 服务器并能成功运行,你可以运行任意的 CGI 程序,比如 Perl 或 Shell 等。

第一个 CGI 程序

请看下面的 C++ 程序:

#include <iostream>
using namespace std;int main ()
{cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>Hello World - 第一个 CGI 程序</title>\n";cout << "</head>\n";cout << "<body>\n";cout << "<h2>Hello World! 这是我的第一个 CGI 程序</h2>\n";cout << "</body>\n";cout << "</html>\n";return 0;
}

编译上面的代码,把可执行文件命名为 cplusplus.cgi,并把这个文件保存在 /var/www/cgi-bin 目录中。在运行 CGI 程序之前,请使用 chmod 755 cplusplus.cgi UNIX 命令来修改文件模式,确保文件可执行。访问可执行文件,您会看到下面的输出:

Hello World! 这是我的第一个 CGI 程序

上面的 C++ 程序是一个简单的程序,把它的输出写在 STDOUT 文件上,即显示在屏幕上。在这里,值得注意一点,第一行输出 Content-type:text/html\r\n\r\n。这一行发送回浏览器,并指定要显示在浏览器窗口上的内容类型。您必须理解 CGI 的基本概念,这样才能进一步使用 Python 编写更多复杂的 CGI 程序。C++ CGI 程序可以与任何其他外部的系统(如 RDBMS)进行交互。

HTTP 头信息

行 Content-type:text/html\r\n\r\n 是 HTTP 头信息的组成部分,它被发送到浏览器,以便更好地理解页面内容。HTTP 头信息的形式如下:

HTTP 字段名称: 字段内容 例如 Content-type: text/html\r\n\r\n

还有一些其他的重要的 HTTP 头信息,这些在您的 CGI 编程中都会经常被用到。

头信息描述
Content-type:MIME 字符串,定义返回的文件格式。例如 Content-type:text/html。
Expires:Date 信息变成无效的日期。浏览器使用它来判断一个页面何时需要刷新。一个有效的日期字符串的格式应为 01 Jan 1998 12:00:00 GMT。
Location:URL 这个 URL 是指应该返回的 URL,而不是请求的 URL。你可以使用它来重定向一个请求到任意的文件。
Last-modified:Date 资源的最后修改日期。
Content-length:N 要返回的数据的长度,以字节为单位。浏览器使用这个值来表示一个文件的预计下载时间。
Set-Cookie:String 通过 string 设置 cookie。

CGI 环境变量

所有的 CGI 程序都可以访问下列的环境变量。这些变量在编写 CGI 程序时扮演了非常重要的角色。

变量名描述
CONTENT_TYPE内容的数据类型。当客户端向服务器发送附加内容时使用。例如,文件上传等功能。
CONTENT_LENGTH查询的信息长度。只对 POST 请求可用。
HTTP_COOKIE以键 & 值对的形式返回设置的 cookies。
HTTP_USER_AGENT用户代理请求标头字段,递交用户发起请求的有关信息,包含了浏览器的名称、版本和其他平台性的附加信息。
PATH_INFOCGI 脚本的路径。
QUERY_STRING通过 GET 方法发送请求时的 URL 编码信息,包含 URL 中问号后面的参数。
REMOTE_ADDR发出请求的远程主机的 IP 地址。这在日志记录和认证时是非常有用的。
REMOTE_HOST发出请求的主机的完全限定名称。如果此信息不可用,则可以用 REMOTE_ADDR 来获取 IP 地址。
REQUEST_METHOD用于发出请求的方法。最常见的方法是 GET 和 POST。
SCRIPT_FILENAMECGI 脚本的完整路径。
SCRIPT_NAMECGI 脚本的名称。
SERVER_NAME服务器的主机名或 IP 地址。
SERVER_SOFTWARE服务器上运行的软件的名称和版本。

下面的 CGI 程序列出了所有的 CGI 变量。

#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;const string ENV[ 24 ] = {                 "COMSPEC", "DOCUMENT_ROOT", "GATEWAY_INTERFACE",   "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING",             "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION",         "HTTP_HOST", "HTTP_USER_AGENT", "PATH",            "QUERY_STRING", "REMOTE_ADDR", "REMOTE_PORT",      "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME","SCRIPT_NAME", "SERVER_ADDR", "SERVER_ADMIN",      "SERVER_NAME","SERVER_PORT","SERVER_PROTOCOL",     "SERVER_SIGNATURE","SERVER_SOFTWARE" };   int main ()
{cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>CGI 环境变量</title>\n";cout << "</head>\n";cout << "<body>\n";cout << "<table border = \"0\" cellspacing = \"2\">";for ( int i = 0; i < 24; i++ ){cout << "<tr><td>" << ENV[ i ] << "</td><td>";// 尝试检索环境变量的值char *value = getenv( ENV[ i ].c_str() );  if ( value != 0 ){cout << value;                                 }else{cout << "环境变量不存在。";}cout << "</td></tr>\n";}cout << "</table><\n";cout << "</body>\n";cout << "</html>\n";return 0;
}

C++ CGI 库

在真实的实例中,您需要通过 CGI 程序执行许多操作。这里有一个专为 C++ 程序而编写的 CGI 库,我们可以从 ftp://ftp.gnu.org/gnu/cgicc/ 上下载这个 CGI 库,并按照下面的步骤安装库:

$ tar xzf cgicc-X.X.X.tar.gz
$ cd cgicc-X.X.X/
$ ./configure --prefix=/usr
$ make
$ make install
注意:libcgicc.so 和 libcgicc.a 库会被安装到/usr/lib目录下,需执行拷贝命令:

$ sudo cp /usr/lib/libcgicc.* /usr/lib64/
才能使 CGI 程序自动找到 libcgicc.so 动态链接库。

您可以点击 C++ CGI Lib Documentation,查看相关的库文档。

GET 和 POST 方法
您可能有遇到过这样的情况,当您需要从浏览器传递一些信息到 Web 服务器,最后再传到 CGI 程序。通常浏览器会使用两种方法把这个信息传到 Web 服务器,分别是 GET 和 POST 方法。

使用 GET 方法传递信息
GET 方法发送已编码的用户信息追加到页面请求中。页面和已编码信息通过 ? 字符分隔开,如下所示:

http://www.test.com/cgi-bin/cpp.cgi?key1=value1&key2=value2
GET 方法是默认的从浏览器向 Web 服务器传信息的方法,它会在浏览器的地址栏中生成一串很长的字符串。当您向服务器传密码或其他一些敏感信息时,不要使用 GET 方法。GET 方法有大小限制,在一个请求字符串中最多可以传 1024 个字符。

当使用 GET 方法时,是使用 QUERY_STRING http 头来传递信息,在 CGI 程序中可使用 QUERY_STRING 环境变量来访问。

您可以通过在 URL 后跟上简单连接的键值对,也可以通过使用 HTML 标签的 GET 方法来传信息。

简单的 URL 实例:Get 方法
下面是一个简单的 URL,使用 GET 方法传递两个值给 cpp_get.cgi 程序。

/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

下面的实例生成 cpp_get.cgi CGI 程序,用于处理 Web 浏览器给出的输入。通过使用 C++ CGI 库,可以很容易地访问传递的信息:

实例
#include
#include
#include
#include <stdio.h>
#include <stdlib.h>

#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main ()
{
Cgicc formData;

cout << “Content-type:text/html\r\n\r\n”;
cout << “\n”;
cout << “\n”;
cout << “使用 GET 和 POST 方法\n”;
cout << “\n”;
cout << “\n”;

form_iterator fi = formData.getElement(“first_name”);
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << “名:” << **fi << endl;
}else{
cout << “No text entered for first name” << endl;
}
cout << “
\n”;
fi = formData.getElement(“last_name”);
if( !fi->isEmpty() &&fi != (*formData).end()) {
cout << “姓:” << **fi << endl;
}else{
cout << “No text entered for last name” << endl;
}
cout << “
\n”;

cout << “\n”;
cout << “\n”;

return 0;
}
现在,编译上面的程序,如下所示:

$g++ -o cpp_get.cgi cpp_get.cpp -lcgicc
生成 cpp_get.cgi,并把它放在 CGI 目录中,并尝试使用下面的链接进行访问:

/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI

这会产生以下结果:

名:ZARA
姓:ALI
简单的表单实例:GET 方法
下面是一个简单的实例,使用 HTML 表单和提交按钮传递两个值。我们将使用相同的 CGI 脚本 cpp_get.cgi 来处理输入。

名:

姓:

下面是上述表单的实际输出,请输入名和姓,然后点击提交按钮查看结果。

使用 POST 方法传递信息
一个更可靠的向 CGI 程序传递信息的方法是 POST 方法。这种方法打包信息的方式与 GET 方法相同,不同的是,它不是把信息以文本字符串形式放在 URL 中的 ? 之后进行传递,而是把它以单独的消息形式进行传递。该消息是以标准输入的形式传给 CGI 脚本的。

我们同样使用 cpp_get.cgi 程序来处理 POST 方法。让我们以同样的例子,通过使用 HTML 表单和提交按钮来传递两个值,只不过这次我们使用的不是 GET 方法,而是 POST 方法,如下所示:

名:
姓: 向 CGI 程序传递复选框数据 当需要选择多个选项时,我们使用复选框。

下面的 HTML 代码实例是一个带有两个复选框的表单:

数学 物理 下面的 C++ 程序会生成 cpp_checkbox.cgi 脚本,用于处理 Web 浏览器通过复选框给出的输入。

实例
#include
#include
#include
#include <stdio.h>
#include <stdlib.h>

#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main ()
{
Cgicc formData;
bool maths_flag, physics_flag;

cout << “Content-type:text/html\r\n\r\n”;
cout << “\n”;
cout << “\n”;
cout << “向 CGI 程序传递复选框数据\n”;
cout << “\n”;
cout << “\n”;

maths_flag = formData.queryCheckbox(“maths”);
if( maths_flag ) {
cout << "Maths Flag: ON " << endl;
}else{
cout << "Maths Flag: OFF " << endl;
}
cout << “
\n”;

physics_flag = formData.queryCheckbox(“physics”);
if( physics_flag ) {
cout << "Physics Flag: ON " << endl;
}else{
cout << "Physics Flag: OFF " << endl;
}
cout << “
\n”;
cout << “\n”;
cout << “\n”;

return 0;
}
向 CGI 程序传递单选按钮数据
当只需要选择一个选项时,我们使用单选按钮。

下面的 HTML 代码实例是一个带有两个单选按钮的表单:

数学 物理 下面的 C++ 程序会生成 cpp_radiobutton.cgi 脚本,用于处理 Web 浏览器通过单选按钮给出的输入。

实例
#include
#include
#include
#include <stdio.h>
#include <stdlib.h>

#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main ()
{
Cgicc formData;

cout << “Content-type:text/html\r\n\r\n”;
cout << “\n”;
cout << “\n”;
cout << “向 CGI 程序传递单选按钮数据\n”;
cout << “\n”;
cout << “\n”;

form_iterator fi = formData.getElement(“subject”);
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << "Radio box selected: " << **fi << endl;
}

cout << “
\n”;
cout << “\n”;
cout << “\n”;

return 0;
}
向 CGI 程序传递文本区域数据
当需要向 CGI 程序传递多行文本时,我们使用 TEXTAREA 元素。

下面的 HTML 代码实例是一个带有 TEXTAREA 框的表单:

请在这里输入文本... 下面的 C++ 程序会生成 cpp_textarea.cgi 脚本,用于处理 Web 浏览器通过文本区域给出的输入。

实例
#include
#include
#include
#include <stdio.h>
#include <stdlib.h>

#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main ()
{
Cgicc formData;

cout << “Content-type:text/html\r\n\r\n”;
cout << “\n”;
cout << “\n”;
cout << “向 CGI 程序传递文本区域数据\n”;
cout << “\n”;
cout << “\n”;

form_iterator fi = formData.getElement(“textcontent”);
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << "Text Content: " << **fi << endl;
}else{
cout << “No text entered” << endl;
}

cout << “
\n”;
cout << “\n”;
cout << “\n”;

return 0;
}
向 CGI 程序传递下拉框数据
当有多个选项可用,但只能选择一个或两个选项时,我们使用下拉框。

下面的 HTML 代码实例是一个带有下拉框的表单:

数学 物理 下面的 C++ 程序会生成 cpp_dropdown.cgi 脚本,用于处理 Web 浏览器通过下拉框给出的输入。

实例
#include
#include
#include
#include <stdio.h>
#include <stdlib.h>

#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main ()
{
Cgicc formData;

cout << “Content-type:text/html\r\n\r\n”;
cout << “\n”;
cout << “\n”;
cout << “向 CGI 程序传递下拉框数据\n”;
cout << “\n”;
cout << “\n”;

form_iterator fi = formData.getElement(“dropdown”);
if( !fi->isEmpty() && fi != (*formData).end()) {
cout << "Value Selected: " << **fi << endl;
}

cout << “
\n”;
cout << “\n”;
cout << “\n”;

return 0;
}
在 CGI 中使用 Cookies
HTTP 协议是一种无状态的协议。但对于一个商业网站,它需要在不同页面间保持会话信息。例如,一个用户在完成多个页面的步骤之后结束注册。但是,如何在所有网页中保持用户的会话信息。

在许多情况下,使用 cookies 是记忆和跟踪有关用户喜好、购买、佣金以及其他为追求更好的游客体验或网站统计所需信息的最有效的方法。

它是如何工作的
服务器以 cookie 的形式向访客的浏览器发送一些数据。如果浏览器接受了 cookie,则 cookie 会以纯文本记录的形式存储在访客的硬盘上。现在,当访客访问网站上的另一个页面时,会检索 cookie。一旦找到 cookie,服务器就知道存储了什么。

cookie 是一种纯文本的数据记录,带有 5 个可变长度的字段:

Expires : cookie 的过期日期。如果此字段留空,cookie 会在访客退出浏览器时过期。
Domain : 网站的域名。
Path : 设置 cookie 的目录或网页的路径。如果您想从任意的目录或网页检索 cookie,此字段可以留空。
Secure : 如果此字段包含单词 “secure”,那么 cookie 只能通过安全服务器进行检索。如果此字段留空,则不存在该限制。
Name=Value : cookie 以键值对的形式被设置和获取。
设置 Cookies
向浏览器发送 cookies 是非常简单的。这些 cookies 会在 Content-type 字段之前,与 HTTP 头一起被发送。假设您想设置 UserID 和 Password 为 cookies,设置 cookies 的步骤如下所示:

实例
#include
using namespace std;

int main ()
{

cout << “Set-Cookie:UserID=XYZ;\r\n”;
cout << “Set-Cookie:Password=XYZ123;\r\n”;
cout << “Set-Cookie:Domain=www.w3cschool.cc;\r\n”;
cout << “Set-Cookie:Path=/perl;\n”;
cout << “Content-type:text/html\r\n\r\n”;

cout << “\n”;
cout << “\n”;
cout << “CGI 中的 Cookies\n”;
cout << “\n”;
cout << “\n”;

cout << “设置 cookies” << endl;

cout << “
\n”;
cout << “\n”;
cout << “\n”;

return 0;
}
从这个实例中,我们了解了如何设置 cookies。我们使用 Set-Cookie HTTP 头来设置 cookies。

在这里,有一些设置 cookies 的属性是可选的,比如 Expires、Domain 和 Path。值得注意的是,cookies 是在发送行 "Content-type:text/html\r\n\r\n 之前被设置的。

编译上面的程序,生成 setcookies.cgi,并尝试使用下面的链接设置 cookies。它会在您的计算机上设置四个 cookies:

/cgi-bin/setcookies.cgi

获取 Cookies
检索所有设置的 cookies 是非常简单的。cookies 被存储在 CGI 环境变量 HTTP_COOKIE 中,且它们的形式如下:

key1=value1;key2=value2;key3=value3…
下面的实例演示了如何获取 cookies。

实例
#include
#include
#include
#include <stdio.h>
#include <stdlib.h>

#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main ()
{
Cgicc cgi;
const_cookie_iterator cci;

cout << “Content-type:text/html\r\n\r\n”;
cout << “\n”;
cout << “\n”;
cout << “CGI 中的 Cookies\n”;
cout << “\n”;
cout << “\n”;
cout << “<table border = “0” cellspacing = “2”>”;

// 获取环境变量
const CgiEnvironment& env = cgi.getEnvironment();

for( cci = env.getCookieList().begin();
cci != env.getCookieList().end();
++cci )
{
cout << “” << cci->getName() << “”;
cout << cci->getValue();
cout << “\n”;
}
cout << “<\n”;

cout << “
\n”;
cout << “\n”;
cout << “\n”;

return 0;
}
现在,编译上面的程序,生成 getcookies.cgi,并尝试使用下面的链接获取您的计算机上所有可用的 cookies:

/cgi-bin/getcookies.cgi

这会产生一个列表,显示了上一节中设置的四个 cookies 以及您的计算机上所有其他的 cookies:

UserID XYZ
Password XYZ123
Domain www.w3cschool.cc
Path /perl
文件上传实例
为了上传一个文件,HTML 表单必须把 enctype 属性设置为 multipart/form-data。带有文件类型的 input 标签会创建一个 “Browse” 按钮。

文件:

这段代码的结果是下面的表单:

文件:未选择任何文件

注意:上面的实例已经故意禁用了保存上传的文件在我们的服务器上。您可以在自己的服务器上尝试上面的代码。

下面是用于处理文件上传的脚本 cpp_uploadfile.cpp:

实例
#include
#include
#include
#include <stdio.h>
#include <stdlib.h>

#include <cgicc/CgiDefs.h>
#include <cgicc/Cgicc.h>
#include <cgicc/HTTPHTMLHeader.h>
#include <cgicc/HTMLClasses.h>

using namespace std;
using namespace cgicc;

int main ()
{
Cgicc cgi;

cout << “Content-type:text/html\r\n\r\n”;
cout << “\n”;
cout << “\n”;
cout << “CGI 中的文件上传\n”;
cout << “\n”;
cout << “\n”;

// 获取要被上传的文件列表
const_file_iterator file = cgi.getFile(“userfile”);
if(file != cgi.getFiles().end()) {
// 在 cout 中发送数据类型
cout << HTTPContentHeader(file->getDataType());
// 在 cout 中写入内容
file->writeToStream(cout);
}
cout << “<文件上传成功>\n”;
cout << “\n”;
cout << “\n”;

return 0;
}
上面的实例是在 cout 流中写入内容,但您可以打开文件流,并把上传的文件内容保存在目标位置的某个文件中。

相关文章:

C++ Web 编程

什么是 CGI&#xff1f; 公共网关接口&#xff08;CGI&#xff09;&#xff0c;是一套标准&#xff0c;定义了信息是如何在 Web 服务器和客户端脚本之间进行交换的。CGI 规范目前是由 NCSA 维护的&#xff0c;NCSA 定义 CGI 如下&#xff1a;公共网关接口&#xff08;CGI&…...

docker笔记整理

Docker 安装 添加yum源 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 安装docker yum -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin 启动docker systemctl start docker 查看docker状态 s…...

什么是git,怎样下载安装?

简介&#xff1a; 应用场景&#xff1a; 应用场景&#xff1a;团队企业开发 作用&#xff1a; 安装&#xff1a; 1.网址&#xff1a;Git - Downloads 很卡很慢 2.可以选择镜像网站下载&#xff08;推荐&#xff09; CNPM Binaries Mirror...

Camille-学习笔记-测试流程和测试设计

## 测试用例学习路线 startmindmap * 测试用例 ** 黑盒测试方法论 *** 等价类 *** 边界值 *** 因果图 *** 判定表 *** 场景法 *** 基于模型的测试 ** 白盒测试方法论 ** 测试用例基础概念 ** 测试用例设计 ** 面试测试用例设计 ** 常用测试策略与测试手段 endmindmap **测试用…...

【Python笔记-设计模式】建造者模式

一、说明 又称生成器&#xff0c;是一种创建型设计模式&#xff0c;使其能够分步骤创建复杂对象。允许使用相同的创建代码生成不同类型和形式的对象。 (一) 解决问题 对象的创建问题&#xff1a;当一个对象的构建过程复杂&#xff0c;且部分构建过程相互独立时&#xff0c;可…...

【LVGL源码移植】

LVGL源码移植 ■ LVGL源码移植一&#xff1a;下载LVGL源码二&#xff1a;修改LVGL文件夹1: 将这5个文件&#xff0c;复制到一个新的文件夹2: 简化文件&#xff0c;减少内存消耗&#xff08;去除不必要的文件&#xff09;3: 为了规范化&#xff0c;我们将下列文件进行重命名 三&…...

双非本科准备秋招(14.2)—— 进程与线程

进程 进程是运行着的程序&#xff0c;是程序在操作系统的一次执行过程&#xff0c;进程是操作系统分配资源的基本单位。 启动一个java程序&#xff0c;操作系统就会创建一个java进程 进程也可以看作一个程序的实例&#xff0c;大部分程序可以运行多个实例进程&#xff0c;比如记…...

数据结构和算法笔记5:堆和优先队列

今天来讲一下堆&#xff0c;在网上看到一个很好的文章&#xff0c;不过它实现堆是用Golang写的&#xff0c;我这里打算用C实现一下&#xff1a; Golang: Heap data structure 1. 基本概念 满二叉树&#xff08;二叉树每层节点都是满的&#xff09;&#xff1a; 完全二叉树&a…...

第8章 SpringBoot任务管理

学习目标 熟悉SpringBoot整合异步任务的实现 熟悉SpringBoot整合定时任务的实现 熟悉SpringBoot整合邮件任务的实现 开发web应用时,多数应用都具备任务调度功能。常见的任务包括异步任务,定时任务和发邮件任务。我们以数据库报表为例看看任务调度如何帮助改善系统设计。报表可…...

Qt5 基于OpenGL实现六轴机械臂三维仿真

需求 在Qt中通过OPenGL方式加载三维模型STL文件&#xff0c;然后将多个结构的STL文件类型的模型进行组装&#xff0c;形成6轴机械臂三维模型的显示&#xff0c;并且可以对每个关节进行关节角度的控制。 新建一个C类STLFileLoader&#xff0c;用于加载STL文件&#xff0c;并进…...

路由进阶

文章目录 1.路由的封装抽离2.声明式导航 - 导航链接3.声明式导航-两个类名自定义匹配的类名 4.声明式导航 - 跳转传参查询参数传参动态路传参两种传参方式的区别动态路由参数可选符 5.Vue路由 - 重定向6.Vue路由 - 4047.Vue路由 - 模式设置8.编程式导航 - 两种路由跳转9.编程式…...

分类预测 | Matlab实现SCN-Adaboost随机配置网络模型SCN的Adaboost数据分类预测/故障识别

分类预测 | Matlab实现SCN-Adaboost随机配置网络模型SCN的Adaboost数据分类预测/故障识别 目录 分类预测 | Matlab实现SCN-Adaboost随机配置网络模型SCN的Adaboost数据分类预测/故障识别分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现SCN-Adaboost随机配置网…...

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之TextPicker组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之TextPicker组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、TextPicker组件 TextClock组件通过文本将当前系统时间显示在设备上。支持不…...

linux中vim的操作

(码字不易&#xff0c;关注一下吧w~~w) 命令模式&#xff1a; 当我们按下esc键时&#xff0c;我们会进入命令模式&#xff1b;当使用vi打开一个文件时也是进入命令模式。 光标移动&#xff1a; 1 保存退出&#xff1a;ZZ 2 代码格式化&#xff1a;ggG 3 光标移动&#xff…...

《统计学习方法:李航》笔记 从原理到实现(基于python)-- 第5章 决策树

文章目录 第5章 决策树5.1 决策树模型与学习5.1.1 决策树模型5.1.2 决策树与if-then规则5.1.3 决策树与条件概率分布5.1.4 决策树学习5.2 特征选择5.2.1 特征选择问题5.2.2 信息增益5.2.3 信息增益比5.3.1 ID3算法5.3.2 C4.5的生成算法5.4 决策树的剪枝5.5 CART算法5.5.1 CART生…...

【C++11(一)】列表初始化and右值引用

一、 统一的列表初始化 1.1 &#xff5b;&#xff5d;初始化 在C98中&#xff0c;标准允许 使用花括号{}对数组或者结构体元素 进行统一的列表初始值设定 C11扩大了用大括号 括起的列表(初始化列表)的使用范围 使其可用于所有的内置类型和 用户自定义的类型 使用初始化列表时…...

为什么SSL会握手失败?SSL握手失败原因及解决方案

随着网络安全技术的发展&#xff0c;SSL证书作为网站数据安全的第一道防线&#xff0c;被越来越多的企业选择。SSL证书使用的是SSL协议&#xff0c;而SSL握手是SSL协议当中最重要的一部分。当部署SSL证书时&#xff0c;如果服务器和客户端之间无法建立安全连接&#xff0c;就会…...

STM32——智能小车

STM32——智能小车 硬件接线 B-1A – PB0 B-1B – PB1 A-1A – PB2 A-1B – PB10 其余接线参考51单片机小车项目。 1.让小车动起来 motor.c #include "motor.h" void goForward(void) {// 左轮HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO…...

开源:基于Vue3.3 + TS + Vant4 + Vite5 + Pinia + ViewPort适配..搭建的H5移动端开发模板

vue3.3-Mobile-template 基于Vue3.3 TS Vant4 Vite5 Pinia ViewPort适配 Sass Axios封装 vconsole调试工具&#xff0c;搭建的H5移动端开发模板&#xff0c;开箱即用的。 环境要求&#xff1a; Node:16.20.1 pnpm:8.14.0 必须装上安装pnpm&#xff0c;没装的看这篇…...

缩略图保持加密(thumbnail-preserving encryption, TPE)的理论基础

这涉及到一些视觉心理学等方面知识: 1、参考文献: 云存储图像缩略图保持的加密研究进展(中国图像图形学报) 一些视觉心理学的研究为TPE的成功实现提供了理论基础。Potter(1975, 1976)的研究表明人类的视觉系统能够在100 ms内从一个新场景中提取出相应的语义信息;250 ms内…...

nodejs+vue+mysql校园失物招领网站38tp1

本高校失物招领平台是为了提高用户查阅信息的效率和管理人员管理信息的工作效率&#xff0c;可以快速存储大量数据&#xff0c;还有信息检索功能&#xff0c;这大大的满足了用户和管理员这两者的需求。操作简单易懂&#xff0c;合理分析各个模块的功能&#xff0c;尽可能优化界…...

GEDepth:Ground Embedding for Monocular Depth Estimation

参考代码&#xff1a;gedepth 出发点与动机 相机的外参告诉了相机在世界坐标系下的位置信息&#xff0c;那么可以用这个外参构建一个地面基础深度作为先验&#xff0c;后续只需要在这个地面基础深度先验基础上添加offset就可以得到结果深度&#xff0c;这样可以极大简化深度估…...

校园圈子论坛系统--APP小程序H5,前后端源码交付,支持二开!uniAPP+PHP书写!

随着移动互联网的快速发展&#xff0c;校园社交成为了大学生们日常生活中重要的一部分。为了方便校园内学生的交流和互动&#xff0c;校园社交小程序逐渐走入人们的视野。本文将探讨校园社交小程序的开发以及其带来的益处。 校园社交小程序的开发涉及许多技术和设计方面。首先&…...

VMware vCenter告警:vSphere UI运行状况警报

vSphere UI运行状况警报 不会详细显示告警的具体内容&#xff0c;需要我们自己进一步确认告警原因。 vSphere UI运行状况警报是一种监控工具&#xff0c;用于检测vSphere环境中的潜在问题。当警报触发时&#xff0c;通常表示系统遇到了影响性能或可用性的问题。解决vSphere UI…...

C# 引用同一个dll不同版本的程序集

因为项目需要所以必须在项目中引用不同版本的同一程序集 我要引用的文件是newtonsoft.json.dll 两个版本为12.0.0.0 和4.0.0.0 1.如果已经先引入了newtonsoft.json 12.0.0.0版本的程序集&#xff0c;如果直接引入另一个版本的程序集的话会提示不成功&#xff0c;所以先将另一个…...

单机搭建hadoop环境(包括hdfs、yarn、hive)

单机可以搭建伪分布式hadoop环境&#xff0c;用来测试和开发使用&#xff0c;hadoop包括&#xff1a; hdfs服务器 yarn服务器&#xff0c;yarn的前提是hdfs服务器&#xff0c; 在前面两个的基础上&#xff0c;课可以搭建hive服务器&#xff0c;不过hive不属于hadoop的必须部…...

LEETCODE 170. 交易逆序对的总数

class Solution { public:int reversePairs(vector<int>& record) {if(record.size()<1)return 0;//归并 递归int left,right;left0;rightrecord.size()-1;int nummergeSort(left,right,record);return num;}int mergeSort(int left,int right, vector<int>…...

「HarmonyOS」EventHub事件通知详细使用方法

需求背景&#xff1a; 在开发过程中&#xff0c;肯定会出现触发特定事件&#xff0c;需要全局进行通知&#xff0c;与之相关的部分进行执行相应的修改方法。举个例子&#xff1a;修改了用户个人昵称&#xff0c;需要进行全局通知&#xff0c;在涉及昵称的部分收到通知后&#…...

为什么golang不支持可重入锁呢?

为什么golang不需要可重入锁&#xff1f; 在工程中使用锁的原因在于为了保护不变量&#xff0c;也可以用于保护内、外部的不变量。 基于此&#xff0c;Go 在互斥锁设计上会遵守这几个原则。如下&#xff1a; 在调用 mutex.Lock 方法时&#xff0c;要保证这些变量的不变性保持…...

聊一聊Tomcat的架构和运行流程,尽量通俗易懂一点

1、Tomcat的架构 这里可以看出 A、一个Tomcat就是一个Server&#xff0c;一个Server下会有多个Service&#xff0c; B、Service只负责封装多个Connector和一个Container&#xff08;Service本身不是容器&#xff0c;可以看做只是用来包装Connector和Container的壳&#xff0c…...