开心档开发入门网之C++ Web 编程
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 fromall
</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";return0;
}编译上面的代码,把可执行文件命名为 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_INFO | CGI 脚本的路径。 |
QUERY_STRING | 通过 GET 方法发送请求时的 URL 编码信息,包含 URL 中问号后面的参数。 |
REMOTE_ADDR | 发出请求的远程主机的 IP 地址。这在日志记录和认证时是非常有用的。 |
REMOTE_HOST | 发出请求的主机的完全限定名称。如果此信息不可用,则可以用 REMOTE_ADDR 来获取 IP 地址。 |
REQUEST_METHOD | 用于发出请求的方法。最常见的方法是 GET 和 POST。 |
SCRIPT_FILENAME | CGI 脚本的完整路径。 |
SCRIPT_NAME | CGI 脚本的名称。 |
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";return0;
}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=value2GET 方法是默认的从浏览器向 Web 服务器传信息的方法,它会在浏览器的地址栏中生成一串很长的字符串。当您向服务器传密码或其他一些敏感信息时,不要使用 GET 方法。GET 方法有大小限制,在一个请求字符串中最多可以传 1024 个字符。
当使用 GET 方法时,是使用 QUERY_STRING http 头来传递信息,在 CGI 程序中可使用 QUERY_STRING 环境变量来访问。
您可以通过在 URL 后跟上简单连接的键值对,也可以通过使用 HTML <FORM> 标签的 GET 方法来传信息。
简单的 URL 实例:Get 方法
下面是一个简单的 URL,使用 GET 方法传递两个值给 hello_get.py 程序。
/cgi-bin/cpp_get.cgi?first_name=ZARA&last_name=ALI
下面的实例生成 cpp_get.cgi CGI 程序,用于处理 Web 浏览器给出的输入。通过使用 C++ CGI 库,可以很容易地访问传递的信息:
实例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespace std;
usingnamespace cgicc;intmain(){Cgicc formData;cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>使用 GET 和 POST 方法</title>\n";cout << "</head>\n";cout << "<body>\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 << "<br/>\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 << "<br/>\n";cout << "</body>\n";cout << "</html>\n";return0;
}现在,编译上面的程序,如下所示:
$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 来处理输入。
<form action="/cgi-bin/cpp_get.cgi" method="get">
名:<inputtype="text" name="first_name"> <br />姓:<inputtype="text" name="last_name" />
<inputtype="submit" value="提交" />
</form>下面是上述表单的实际输出,请输入名和姓,然后点击提交按钮查看结果。
使用 POST 方法传递信息
一个更可靠的向 CGI 程序传递信息的方法是 POST 方法。这种方法打包信息的方式与 GET 方法相同,不同的是,它不是把信息以文本字符串形式放在 URL 中的 ? 之后进行传递,而是把它以单独的消息形式进行传递。该消息是以标准输入的形式传给 CGI 脚本的。
我们同样使用 cpp_get.cgi 程序来处理 POST 方法。让我们以同样的例子,通过使用 HTML 表单和提交按钮来传递两个值,只不过这次我们使用的不是 GET 方法,而是 POST 方法,如下所示:
<form action="/cgi-bin/cpp_get.cgi" method="post">
名:<inputtype="text" name="first_name"><br />
姓:<inputtype="text" name="last_name" /><inputtype="submit" value="提交" />
</form>向 CGI 程序传递复选框数据
当需要选择多个选项时,我们使用复选框。
下面的 HTML 代码实例是一个带有两个复选框的表单:
<form action="/cgi-bin/cpp_checkbox.cgi" method="POST" target="_blank">
<inputtype="checkbox" name="maths" value="on" /> 数学
<inputtype="checkbox" name="physics" value="on" /> 物理
<inputtype="submit" value="选择学科" />
</form>下面的 C++ 程序会生成 cpp_checkbox.cgi 脚本,用于处理 Web 浏览器通过复选框给出的输入。
实例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespace std;
usingnamespace cgicc;intmain(){Cgicc formData;bool maths_flag, physics_flag;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";maths_flag = formData.queryCheckbox("maths");if( maths_flag ) { cout << "Maths Flag: ON " << endl; }else{cout << "Maths Flag: OFF " << endl; }cout << "<br/>\n";physics_flag = formData.queryCheckbox("physics");if( physics_flag ) { cout << "Physics Flag: ON " << endl; }else{cout << "Physics Flag: OFF " << endl; }cout << "<br/>\n";cout << "</body>\n";cout << "</html>\n";return0;
}向 CGI 程序传递单选按钮数据
当只需要选择一个选项时,我们使用单选按钮。
下面的 HTML 代码实例是一个带有两个单选按钮的表单:
<form action="/cgi-bin/cpp_radiobutton.cgi" method="post" target="_blank">
<inputtype="radio" name="subject" value="maths" checked="checked"/> 数学
<inputtype="radio" name="subject" value="physics" /> 物理
<inputtype="submit" value="选择学科" />
</form>下面的 C++ 程序会生成 cpp_radiobutton.cgi 脚本,用于处理 Web 浏览器通过单选按钮给出的输入。
实例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespace std;
usingnamespace cgicc;intmain(){Cgicc formData;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";form_iterator fi = formData.getElement("subject"); if( !fi->isEmpty() && fi != (*formData).end()) { cout << "Radio box selected: " << **fi << endl; }cout << "<br/>\n";cout << "</body>\n";cout << "</html>\n";return0;
}向 CGI 程序传递文本区域数据
当需要向 CGI 程序传递多行文本时,我们使用 TEXTAREA 元素。
下面的 HTML 代码实例是一个带有 TEXTAREA 框的表单:
<formaction="/cgi-bin/cpp_textarea.cgi"method="post"target="_blank"><textareaname="textcontent"cols="40"rows="4">
请在这里输入文本...
</textarea><inputtype="submit"value="提交" /></form>下面的 C++ 程序会生成 cpp_textarea.cgi 脚本,用于处理 Web 浏览器通过文本区域给出的输入。
实例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespace std;
usingnamespace cgicc;intmain(){Cgicc formData;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";form_iterator fi = formData.getElement("textcontent"); if( !fi->isEmpty() && fi != (*formData).end()) { cout << "Text Content: " << **fi << endl; }else{cout << "No text entered" << endl; }cout << "<br/>\n";cout << "</body>\n";cout << "</html>\n";return0;
}向 CGI 程序传递下拉框数据
当有多个选项可用,但只能选择一个或两个选项时,我们使用下拉框。
下面的 HTML 代码实例是一个带有下拉框的表单:
<formaction="/cgi-bin/cpp_dropdown.cgi"method="post"target="_blank"><selectname="dropdown"><optionvalue="Maths"selected>数学</option><optionvalue="Physics">物理</option></select><inputtype="submit"value="提交"/></form>下面的 C++ 程序会生成 cpp_dropdown.cgi 脚本,用于处理 Web 浏览器通过下拉框给出的输入。
实例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespace std;
usingnamespace cgicc;intmain(){Cgicc formData;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";form_iterator fi = formData.getElement("dropdown"); if( !fi->isEmpty() && fi != (*formData).end()) { cout << "Value Selected: " << **fi << endl; }cout << "<br/>\n";cout << "</body>\n";cout << "</html>\n";return0;
}在 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 <iostream>
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 <<"<html>\n";cout <<"<head>\n";cout <<"<title>CGI 中的 Cookies</title>\n";cout <<"</head>\n";cout <<"<body>\n";cout <<"设置 cookies"<< endl; cout <<"<br/>\n";cout <<"</body>\n";cout <<"</html>\n";return0;
}从这个实例中,我们了解了如何设置 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<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespace std;
usingnamespace cgicc;intmain(){Cgicc cgi;const_cookie_iterator cci;cout << "Content-type:text/html\r\n\r\n";cout << "<html>\n";cout << "<head>\n";cout << "<title>CGI 中的 Cookies</title>\n";cout << "</head>\n";cout << "<body>\n";cout << "<table border = \"0\" cellspacing = \"2\">";// 获取环境变量const CgiEnvironment& env = cgi.getEnvironment();for( cci = env.getCookieList().begin();cci != env.getCookieList().end(); ++cci ){cout << "<tr><td>" << cci->getName() << "</td><td>";cout << cci->getValue(); cout << "</td></tr>\n";}cout << "</table><\n";cout << "<br/>\n";cout << "</body>\n";cout << "</html>\n";return0;
}现在,编译上面的程序,生成 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" 按钮。
<html><body><formenctype="multipart/form-data"action="/cgi-bin/cpp_uploadfile.cgi"method="post"><p>文件:<inputtype="file"name="userfile" /></p><p><inputtype="submit"value="上传" /></p></form></body></html>这段代码的结果是下面的表单: 文件:
**注意:**上面的实例已经故意禁用了保存上传的文件在我们的服务器上。您可以在自己的服务器上尝试上面的代码。
下面是用于处理文件上传的脚本 cpp_uploadfile.cpp:
实例
#include<iostream>#include<vector>#include<string>#include<stdio.h>#include<stdlib.h>#include<cgicc/CgiDefs.h>#include<cgicc/Cgicc.h>#include<cgicc/HTTPHTMLHeader.h>#include<cgicc/HTMLClasses.h>usingnamespace std;
usingnamespace cgicc;intmain(){Cgicc cgi;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";// 获取要被上传的文件列表const_file_iterator file = cgi.getFile("userfile");if(file != cgi.getFiles().end()) {// 在 cout 中发送数据类型cout << HTTPContentHeader(file->getDataType());// 在 cout 中写入内容file->writeToStream(cout);}cout << "<文件上传成功>\n";cout << "</body>\n";cout << "</html>\n";return0;
}上面的实例是在 cout 流中写入内容,但您可以打开文件流,并把上传的文件内容保存在目标位置的某个文件中。
相关文章:
开心档开发入门网之C++ Web 编程
C Web 编程什么是 CGI?公共网关接口(CGI),是一套标准,定义了信息是如何在 Web 服务器和客户端脚本之间进行交换的。CGI 规范目前是由 NCSA 维护的,NCSA 定义 CGI 如下:公共网关接口(…...
C# 和 VB .NET 的纯 FFmpeg 包装器:CSFFmpeg Crack
用于 C# 和 VB .NET 的纯 FFmpeg 包装器buildbuildpassingpassing releasereleasev1.0.3.0v1.0.3.0用于 C# 和 VB .NET Framework(WinForm 和 WPF)和 .NET Core 的纯 FFmpeg 包装器。 截图 主要 Winform 示例有据可查的例子目录: 关于截图好处…...
python外篇(序列化和非序列化)
目录 概念阐述 pickle json msgpack 概念阐述 序列化是指将对象转化为可存储或可传输的数据格式,例如将 Python 对象转化为二进制、JSON 或 XML 等格式,以便于将其存储到文件中或在网络上传输。在Python中,可以使用pickle、json、msgpac…...
Linux总结(二)
基础IO 1.什么叫文件? 我们需要在操作系统的角度理解文件。 文件 = 文件内容 + 属性(所以即使是空文件,也会占空间,因为我们是需要保存文件属性的,属性也是数据,所以占空间) C/C++程序默认会打开三个文件流,叫做标准输入(stdin),标准输出(stdout),标准错误(std…...
【4.1】Socket编程、TCP挥手
TCP连接断开 四次挥手 四次挥手过程 客户端发送FIN报文,客户端进入FIN_WAIT_1状态。 服务端接收报文,发送ACK报文,服务端进入CLOSE_WAIT状态。 客户端收到ACK报文,进入FIN_WAIT_2状态。 服务端处理完数据后,也发送…...
【竞赛经历】CSDN第41期竞赛题解
1 前言 本次的竞赛主要是最后一题,对于完全不懂珠算的人来说还是有点困难的,仅理解题目的意思就花了很多时间,最后侥幸拿了第一个前三。。。 2 题解 本次竞赛分为编程题部分和非编程题部分,其中非编程题部分比较简单。 2.1 非编…...
【Linux学习】信号——预备知识 | 信号产生 | 核心转储
🐱作者:一只大喵咪1201 🐱专栏:《Linux学习》 🔥格言:你只管努力,剩下的交给时间! 信号🔔信号🎵预备知识🎵信号处理方法的注册🔔信号…...
2023中国程序员薪酬报告出炉,你拖后腿了吗?
程序员薪资高已是公认的事实,但是具体高到什么程度呢?近期,全球人力服务公司 Michael Page Internatioal 就发布了《2023 中国大陆薪酬报告》,揭示了中国程序员的薪酬情况。 该报告中一共调研了国内 7 个行业以及 6 大城市不同职…...
Mac下Python3安装及基于Idea开发
本篇文章带大家基于Mac OS操作系统,下载、安装Python环境,并基于Idea编写第一个Demo。 Python3安装 访问Python官网:https://www.python.org/。找到“Download”菜单,点击下载: 此处下载的为Mac的安装包,…...
2017年 团体程序设计天梯赛——题解集
前言: Hello各位童学大家好!😊😊,茫茫题海你我相遇即是缘分呐,或许日复一日的刷题已经让你感到疲惫甚至厌倦了,但是我们真的真的已经达到了我们自身极限了吗?少一点自我感动…...
“唯一靶点”的华堂宁会成控糖爆品吗?
一上市,两次“断货”的货华堂宁有爆品那味儿了。 2022年10月28日华领医药-B(02552.HK)公告华堂宁(多格列艾汀)正式进入商业化,一周后各个渠道便进入到了断货和限售的状态。 对于一个不在传统九大降糖药品…...
Spring《三》DI依赖注入
🍎道阻且长,行则将至。🍓 上一篇:Spring《二》bean的实例化与生命周期 下一篇:敬请期待 目录一、setter注入🍉1.注入引用数据类型2.注入简单数据类型二、构造器注入🍊1.注入引用数据类型2.简单数…...
leetcode 面试题 17.06. 2出现的次数
编写一个方法,计算从 0 到 n (含 n) 中数字 2 出现的次数。 示例: 输入: 25 输出: 9 解释: (2, 12, 20, 21, 22, 23, 24, 25)(注意 22 应该算作两次) 该问题用的方法数数组dp,首先我通过总结规律写出了相关的code。使用一个dp数组记录10i10^i10i以内会出…...
CMake入门教程【基础篇】5.configure_file构建配置
configure_file配置文件 文章目录 知识点实例代码目录代码实现知识点 configure_fileconfigure_file 源文件转换为目标文件 实例 代码目录 |-📁prj4 |-- 🎴CMakeLists.txt |-- 🎴TutorialConfig.h.in |-- 🎴tutorial.cxx 代码实现 /prj4/CMakeLists.…...
软件开发可行性分析——健康食谱小程序
关于软件开发可行性分析先给大家介绍下面几个关键点: 什么是可行性分析? 检查并确定是否值得为项目或产品投入时间、金钱和资源。这样的评估活动称为“可行性分析”。 为什么要进行可行性分析? 在软件项目开发过程中,只要资源…...
ShuffleNet V1 对花数据集训练
目录 1. shufflenet 介绍 分组卷积 通道重排 2. ShuffleNet V1 网络 2.1 shufflenet 的结构 2.2 代码解释 2.3 shufflenet 代码 3. train 训练 4. Net performance on flower datasets 1. shufflenet 介绍 shufflenet的亮点:分组卷积 通道重排 mobilenet …...
测试人员转型是大势所趋:我的10年自动化测试经验分享
做测试十多年,有不少人问过我下面问题: 现在的手工测试真的不行了吗? 测试工程师,三年多快四年的经验,入门自动化测试需要多久? 自学自动化测试到底需要学哪些东西? 不得不说,随着行…...
Pandas高级操作,建议收藏(一)
在数据分析和数据建模的过程中需要对数据进行清洗和整理等工作,有时需要对数据增删字段。下面为大家介绍Pandas对数据的复杂查询、数据类型转换、数据排序的使用。 复杂查询 实际业务需求往往需要按照一定的条件甚至复杂的组合条件来查询数据,接下来为大家介绍如何…...
ASIC-WORLD Verilog(1)一日Verilog
写在前面 在自己准备写一些简单的verilog教程之前,参考了许多资料----asic-world网站的这套verilog教程即是其一。这套教程写得极好,奈何没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。 这是网站原文&…...
数据治理工具项目投标书技术部分-V1.6
本资料来源公开网络,仅供个人学习,请勿商用,如有侵权请联系删除 项目背景 二、项目目标 提供一套后勤数据治理工具部署文件及配套文档,主要技术指标如下: (1)具备数据抽取转换装载、元数据管理、…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
