C 语言 Web 开发:CGI、FastCGI、Nginx 深度解析
一、前言:为什么 Web 开发是 C 语言开发的重要技能?
学习目标
- 理解Web 开发的本质:
C 语言 Web 开发涉及 CGI、FastCGI 和 Nginx 模块技术。CGI 通过环境变量实现服务器与程序通信,FastCGI 改进性能支持长驻进程。Nginx 基于事件驱动模型。文章包含 Hello World 示例及用户登录实战代码,演示请求参数解析与响应生成,并提供 Nginx 配置参考。

💡 Web 开发在 C 语言生态中具有重要地位。随着互联网的普及,Web 开发的需求越来越大,C 语言的高性能和可移植性使其在 Web 开发中占据重要位置。
Web 服务器:接受客户端请求,将请求转发给 CGI 程序
CGI 程序:处理请求,生成响应
客户端:发送请求,接收响应
代码示例 1:CGI 程序——简单的 Hello World
#include <stdio.h>
#include <stdlib.h>
int main() {
// 设置 HTTP 响应头
printf("Content-Type: text/plain\n\n");
// 输出响应内容
printf("Hello from CGI!");
return 0;
}
代码示例 2:CGI 程序——获取 HTTP 请求参数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void decode_url(char* src, char* dst) {
int i = 0, j = 0;
while (src[i]) {
if (src[i] == '%') {
int value;
sscanf(src + i + 1, "%2x", &value);
dst[j++] = (char)value;
i += 3;
} else if (src[i] == '+') {
dst[j++] = ' ';
i++;
} else {
dst[j++] = src[i++];
}
}
dst[j] = '\0';
}
int main() {
// 获取环境变量
char* query_string = getenv("QUERY_STRING");
char* content_type = getenv("CONTENT_TYPE");
char* request_method = getenv("REQUEST_METHOD");
// 输出环境变量信息
printf("Content-Type: text/plain\n\n");
printf("Query String: %s\n", query_string ? query_string : "");
printf("Content Type: %s\n", content_type ? content_type : "");
printf("Request Method: %s\n", request_method ? request_method : "");
if (strcmp(request_method, "GET") == 0 && query_string) {
char* token = strtok(query_string, "&");
while (token) {
char* equals = strchr(token, '=');
if (equals) {
*equals = '\0';
char* key = token;
char* value = equals + 1;
char decoded_key[100], decoded_value[100];
decode_url(key, decoded_key);
decode_url(value, decoded_value);
printf("Parameter: %s = %s\n", decoded_key, decoded_value);
}
token = strtok(NULL, "&");
}
}
return 0;
}
Web 服务器:接受客户端请求,将请求转发给 FastCGI 进程
FastCGI 进程:处理请求,生成响应,保持进程驻留以提高性能
客户端:发送请求,接收响应
代码示例 3:FastCGI 程序——简单的 Hello World
#include <fcgi_stdio.h>
#include <stdlib.h>
int main() {
while (FCGI_Accept() >= 0) {
// 设置 HTTP 响应头
printf("Content-Type: text/plain\n\n");
// 输出响应内容
printf("Hello from FastCGI!");
}
return 0;
}
代码示例 4:FastCGI 程序——获取 HTTP 请求参数
#include <fcgi_stdio.h>
#include <stdlib.h>
#include <string.h>
void decode_url(char* src, char* dst) {
int i = 0, j = 0;
while (src[i]) {
if (src[i] == '%') {
int value;
sscanf(src + i + 1, "%2x", &value);
dst[j++] = (char)value;
i += 3;
} else if (src[i] == '+') {
dst[j++] = ' ';
i++;
} else {
dst[j++] = src[i++];
}
}
dst[j] = '\0';
}
int main() {
while (FCGI_Accept() >= 0) {
// 获取环境变量
char* query_string = getenv("QUERY_STRING");
char* content_type = getenv("CONTENT_TYPE");
char* request_method = getenv("REQUEST_METHOD");
// 输出环境变量信息
printf("Content-Type: text/plain\n\n");
printf("Query String: %s\n", query_string ? query_string : "");
printf("Content Type: %s\n", content_type ? content_type : "");
printf("Request Method: %s\n", request_method ? request_method : "");
if (strcmp(request_method, "GET") == 0 && query_string) {
char* token = strtok(query_string, "&");
while (token) {
char* equals = strchr(token, '=');
if (equals) {
*equals = '\0';
char* key = token;
char* value = equals + 1;
char decoded_key[100], decoded_value[100];
decode_url(key, decoded_key);
decode_url(value, decoded_value);
printf("Parameter: %s = %s\n", decoded_key, decoded_value);
}
token = strtok(NULL, "&");
}
}
}
return 0;
}
事件驱动模型:使用 epoll 等事件通知机制,高效处理并发连接
内存池:统一管理内存分配和释放,避免内存泄漏
多进程模型:Master 进程管理 Worker 进程,Worker 进程处理请求
代码示例 5:Nginx 模块——简单的 Hello World
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r);
static ngx_command_t ngx_http_hello_commands[] = {
{ngx_string("hello_world"), NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL},
ngx_null_command
};
static ngx_http_module_t ngx_http_hello_module_ctx = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
ngx_module_t ngx_http_hello_module = {
NGX_MODULE_V1,
&ngx_http_hello_module_ctx,
ngx_http_hello_commands,
NGX_HTTP_MODULE,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
NGX_MODULE_V1_PADDING
};
static ngx_int_t ngx_http_hello_handler(ngx_http_request_t *r) {
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t out;
// 设置响应头
r->headers_out.content_type.len = sizeof("text/plain") - 1;
r->headers_out.content_type.data = (u_char *)"text/plain";
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = 13;
// 发送响应头
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
// 准备响应内容
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
out.buf = b;
out.next = NULL;
b->pos = (u_char *)"Hello from Nginx!";
b->last = b->pos + 13;
b->memory = 1;
b->last_buf = 1;
// 发送响应内容
return ngx_http_output_filter(r, &out);
}
static ngx_int_t ngx_http_hello_init(ngx_conf_t *cf) {
ngx_http_handler_pt *h;
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
h = ngx_array_push(&clcf->handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_hello_handler;
return NGX_OK;
}
static ngx_http_module_t ngx_http_hello_module_ctx = {
NULL, ngx_http_hello_init, NULL, NULL, NULL, NULL, NULL, NULL
};
代码示例 6:FastCGI 程序——用户登录
#include <fcgi_stdio.h>
#include <stdlib.h>
#include <string.h>
void decode_url(char* src, char* dst) {
int i = 0, j = 0;
while (src[i]) {
if (src[i] == '%') {
int value;
sscanf(src + i + 1, "%2x", &value);
dst[j++] = (char)value;
i += 3;
} else if (src[i] == '+') {
dst[j++] = ' ';
i++;
} else {
dst[j++] = src[i++];
}
}
dst[j] = '\0';
}
int main() {
while (FCGI_Accept() >= 0) {
// 获取环境变量
char* content_type = getenv("CONTENT_TYPE");
char* request_method = getenv("REQUEST_METHOD");
if (strcmp(request_method, "POST") == 0) {
// 获取请求体长度
char* content_length_str = getenv("CONTENT_LENGTH");
int content_length = atoi(content_length_str);
// 读取请求体
char* post_data = (char*)malloc(content_length + 1);
if (post_data) {
fread(post_data, 1, content_length, stdin);
post_data[content_length] = '\0';
// 解析请求体参数
char* username = NULL;
char* password = NULL;
char* token = strtok(post_data, "&");
while (token) {
char* equals = strchr(token, '=');
if (equals) {
*equals = '\0';
char* key = token;
char* value = equals + 1;
char decoded_key[100], decoded_value[100];
decode_url(key, decoded_key);
decode_url(value, decoded_value);
if (strcmp(decoded_key, "username") == 0) {
username = strdup(decoded_value);
} else if (strcmp(decoded_key, "password") == 0) {
password = strdup(decoded_value);
}
}
token = strtok(NULL, "&");
}
// 验证用户
printf("Content-Type: text/plain\n\n");
if (username && password && strcmp(username, "admin") == 0 && strcmp(password, "123456") == 0) {
printf("登录成功!");
} else {
printf("用户名或密码错误!");
}
free(username);
free(password);
free(post_data);
}
} else {
// 发送登录页面
printf("Content-Type: text/html\n\n");
printf("<html>");
printf("<head>");
printf("<title>登录页面</title>");
printf("</head>");
printf("<body>");
printf("<h1>用户登录</h1>");
printf("<form method='post' action='/login'>");
printf("用户名:<input type='text' name='username'><br>");
printf("密码:<input type='password' name='password'><br>");
printf("<input type='submit' value='登录'>");
printf("</form>");
printf("</body>");
printf("</html>");
}
}
return 0;
}
Nginx 配置文件示例:
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html;
}
location /login {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.cgi;
include fastcgi_params;
}
}
✅ CGI 网络编程:通用网关接口,用于 Web 服务器与服务器端程序之间的通信
✅ FastCGI 网络编程:改进了 CGI 的性能,支持进程驻留
✅ Nginx 与 C 语言开发:高性能 Web 服务器和反向代理服务器,支持模块开发
✅ 实战案例分析:使用 C 语言实现简单的 Web 应用,包含登录功能

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online