亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> C语言

掌握 C++ CGI 网络编程:从入门到实战

什么是 CGI?

CGI(Common Gateway Interface,通用网关接口) 是一组标准,定义 Web 服务器与自定义脚本(CGI 程序)之间的信息交换方式。CGI 规范由 NCSA 维护,当前版本为 CGI/1.1,CGI/1.2 正在制定中。

CGI 程序可用 Python、Perl、Shell、C、C++ 等语言编写,作为外部网关程序与 HTTP 服务器交互。

Web 浏览流程与 CGI 角色

  1. 浏览器向 HTTP 服务器请求 URL(文件名)。
  2. 服务器解析 URL 查找文件:找到则返回文件,否则返回错误信息。
  3. 浏览器显示文件或错误信息。

但可配置服务器:当请求特定目录下的文件时,不直接返回文件,而是将其作为程序执行,将程序的输出返回浏览器显示。这就是 CGI 的工作模式。

Web 服务器配置

CGI 程序通常放在预配置的 CGI 目录,惯例为 /var/www/cgi-bin,文件扩展名通常为 .cgi(即使是 C++ 可执行文件)。

Apache 默认配置示例(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 支持并正确配置。

第一个 CGI 程序

#include <iostream>
using namespace std;

int main() {
    // 必须先输出 HTTP 头,指定内容类型
    cout << "Content-type:text/html\r\n\r\n";
    cout << "<html>\n";
    cout << "<head>\n";
    cout << "<title>Hello World - First CGI Program</title>\n";
    cout << "</head>\n";
    cout << "<body>\n";
    cout << "<h2>Hello World! This is my first CGI program</h2>\n";
    cout << "</body>\n";
    cout << "</html>\n";
    return 0;
}

编译后命名为 cplusplus.cgi,放入 /var/www/cgi-bin,执行 chmod 755 cplusplus.cgi 赋予执行权限。

关键点:第一行 Content-type:text/html\r\n\r\n 是 HTTP 头,告知浏览器内容类型,必须在实际内容之前输出,且以双换行符结束。

HTTP 头详解

HTTP 头格式:字段名: 字段内容,如 Content-type: text/html\r\n\r\n。

序号常用 HTTP 头
1Content-type:MIME 类型,如 text/html。
2Expires:过期时间,格式如 01 Jan 1998 12:00:00 GMT。
3Location:重定向 URL。
4Last-modified:资源最后修改时间。
5Content-length:返回数据字节数。
6Set-Cookie:设置 Cookie。

CGI 环境变量

CGI 程序可访问以下关键环境变量:

变量名说明
CONTENT_TYPE客户端发送内容的数据类型(如文件上传)。
CONTENT_LENGTHPOST 请求的查询信息长度。
HTTP_COOKIE客户端 Cookie,键值对形式。
HTTP_USER_AGENT客户端浏览器标识。
PATH_INFOCGI 脚本路径。
QUERY_STRINGGET 请求的 URL 编码参数。
REMOTE_ADDR客户端 IP 地址。
REMOTE_HOST客户端主机名(不可用时用 IP)。
REQUEST_METHOD请求方法(GET/POST 等)。
SCRIPT_FILENAMECGI 脚本完整路径。
SCRIPT_NAMECGI 脚本名称。
SERVER_NAME服务器主机名或 IP。
SERVER_SOFTWARE服务器软件名称版本。

示例:列出所有环境变量

#include <iostream>
#include <stdlib.h>
#include <string>

using namespace std;

const string ENV[] = {
    "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><head><title>CGI Environment Variables</title></head><body>";
    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) cout << value;
        else cout << "Environment variable does not exist.";
        cout << "</td></tr>\n";
    }
    cout << "</table></body></html>";
    return 0;
}

C++ CGI 库

实际开发推荐使用 cgicc 库,简化表单处理、Cookie、文件上传等操作。下载地址:ftp://ftp.gnu.org/gnu/cgicc/

tar xzf cgicc-X.X.X.tar.gz
cd cgicc-X.X.X/
./configure --prefix=/usr
make
make install

GET 与 POST 方法

GET 方法

参数附加在 URL 后,用 ? 分隔:https://example.com/cgi-bin/cpp.cgi?key1=value1&key2=value2

POST 方法

参数作为独立消息体发送,通过标准输入(stdin)传递给 CGI 程序,无长度限制,更安全。

使用 cgicc 处理 GET/POST 示例

#include <iostream>
#include <vector>
#include <string>
#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 << HTTPHTMLHeader();  // 自动输出 Content-type:text/html
    cout << "<html><head><title>GET/POST Demo</title></head><body>";

    form_iterator fi = formData.getElement("first_name");
    if (!fi->isEmpty() && fi != (*formData).end())
        cout << "First name: " << **fi << "<br/>";
    else
        cout << "No text entered for first name<br/>";

    fi = formData.getElement("last_name");
    if (!fi->isEmpty() && fi != (*formData).end())
        cout << "Last name: " << **fi << "<br/>";
    else
        cout << "No text entered for last name<br/>";

    cout << "</body></html>";
    return 0;
}

编译:g++ -o cpp_get.cgi cpp_get.cpp -lcgicc

表单控件数据处理

复选框

// HTML
<form action="/cgi-bin/cpp_checkbox.cgi" method="POST">
    <input type="checkbox" name="maths" value="on" /> Maths
    <input type="checkbox" name="physics" value="on" /> Physics
    <input type="submit" value="Select Subject" />
</form>

// C++ 处理
bool maths_flag = formData.queryCheckbox("maths");
bool physics_flag = formData.queryCheckbox("physics");

单选按钮

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

文本域

form_iterator fi = formData.getElement("textcontent");
if (!fi->isEmpty() && fi != (*formData).end())
    cout << "Text Content: " << **fi;

下拉框

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

Cookie 处理

HTTP 无状态,Cookie 用于维护会话信息。Cookie 由 5 个字段组成:Expires、Domain、Path、Secure、Name=Value。

设置 Cookie

cout << "Set-Cookie:UserID=XYZ;\r\n";
cout << "Set-Cookie:Password=XYZ123;\r\n";
cout << "Set-Cookie:Domain=www.example.com;\r\n";
cout << "Set-Cookie:Path=/app;\r\n";
cout << "Content-type:text/html\r\n\r\n";  // 必须在 Content-type 之前设置 Cookie

读取 Cookie

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

Cgicc cgi;
const CgiEnvironment& env = cgi.getEnvironment();
for (const_cookie_iterator cci = env.getCookieList().begin();
     cci != env.getCookieList().end(); ++cci) {
    cout << cci->getName() << " = " << cci->getValue() << "<br/>";
}

文件上传

HTML 表单需设置 enctype="multipart/form-data":

<form enctype="multipart/form-data" action="/cgi-bin/cpp_uploadfile.cgi" method="post">
    <p>File: <input type="file" name="userfile" /></p>
    <p><input type="submit" value="Upload" /></p>
</form>

C++ 处理上传文件:

const_file_iterator file = cgi.getFile("userfile");
if (file != cgi.getFiles().end()) {
    cout << HTTPContentHeader(file->getDataType());  // 输出正确的 Content-type
    file->writeToStream(cout);  // 将文件内容写入输出流
    // 实际应用中应保存到服务器文件系统
}

安全提示

C语言

  1. 掌握 C# 命名空间:代码组织、作用域与最佳实践
  2. 掌握 C++ 运算符:六大类型全解析与实战示例
  3. C++ 注释最佳实践:编写可读、可维护代码的注释艺术
  4. C++数组传递给函数实战指南
  5. C 语言编程入门:全面教程指南
  6. C++编程语言:核心特性全景解析
  7. C++常量与字面量完全手册:类型、语法与最佳实践
  8. C++运算符大全:算术/关系/逻辑/位/赋值/杂项与优先级结合性
  9. C++数值类型实战指南:基本类型、数学函数与随机数生成
  10. C++引用详解:核心概念、与指针三大差异及函数参数/返回值应用
  11. C++模板编程指南:泛型编程基石与函数/类模板实战
  12. C++预处理器指令详解:#define宏、条件编译、#/#运算符与预定义宏