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 的架构:

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 None

   Options ExecCGI

   Order allow,deny

   Allow 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_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";

   

   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 <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> 

using namespace std;

using namespace cgicc;

 

int main ()

{

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";

   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 来处理输入。

<form action="/cgi-bin/cpp_get.cgi" method="get">

名:<input type="text" name="first_name"> <br />

 

姓:<input type="text" name="last_name" />

<input type="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">

名:<input type="text" name="first_name"><br />

姓:<input type="text" name="last_name"

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨得江-君临天下wyj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值