作者從 Java Web 轉型嵌入式開發,面臨記憶體受限(Flash 僅 1MB)、無 GC、需手動管理資源等挑戰。本文系統整理 CGI(Common Gateway Interface)在嵌入式 Linux(lighttpd)環境下的原理、關鍵環境變量、表單解析、HTML 輸出與調試技巧,助你快速上手嵌入式 Web 介面開發。
CGI 定義了 Web Server(如 lighttpd)調用外部可執行程式的標準協議。流程:
C 語言 CGI 優勢:編譯執行、二進制不可篡改、執行速度快、佔用資源極低——極適合嵌入式場景。
| 介面 | 用途 | 典型場景 |
|---|---|---|
| 標準輸入 (stdin) | 接收 POST 數據流 | 表單提交、檔案上傳 |
| 環境變量 | 傳遞請求元數據 | QUERY_STRING (GET)、CONTENT_LENGTH、HTTP_COOKIE |
| 標準輸出 (stdout) | 輸出 HTTP 響應 | MIME Head + HTML/JSON/圖片二進制 |
REQUEST_METHOD : GET / POST
CONTENT_LENGTH : POST 數據長度(字節數,必讀,否則無法知曉輸入結束)
CONTENT_TYPE : application/x-www-form-urlencoded (表單預設)
QUERY_STRING : GET 參數 / POST 也可能攜帶
HTTP_COOKIE : 客戶端 Cookie
REMOTE_ADDR : 客戶端 IP
SCRIPT_NAME : CGI 程式路徑
#include <stdio.h>
#include <stdlib.h>
int main() {
char *lenStr = getenv("CONTENT_LENGTH");
int n = lenStr ? atoi(lenStr) : 0;
// 1. 輸出 MIME Head(雙換行結束 header)
printf("Content-Type: text/plain\r\n\r\n");
// 2. 讀取 stdin 並原樣輸出
for (int i = 0; i < n; ++i) {
int ch = getchar();
if (ch == EOF) break;
putchar(ch);
}
fflush(stdout);
return 0;
}
關鍵點:CONTENT_LENGTH 必讀,因 stdin 無 EOF 終止;雙 \r\n 分隔 Header 與 Body。
表單提交格式:name1=value1&name2=value2。特殊字符編碼:
+ → 空格%XX → 十六進制 ASCII(如 %20 = 空格,%3D = =)#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int hexVal(char c) {
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
return 0;
}
int main() {
char *lenStr = getenv("CONTENT_LENGTH");
int n = lenStr ? atoi(lenStr) : 0;
printf("Content-Type: text/plain\r\n\r\n");
for (int i = 0; i < n; ++i) {
int ch = getchar();
if (ch == EOF) break;
switch (ch) {
case '&': putchar('\n'); break; // 鍵值對換行
case '+': putchar(' '); break; // + 轉空格
case '%': // %XX 解碼
if (i + 2 < n) {
int h1 = hexVal(getchar());
int h2 = hexVal(getchar());
putchar((h1 << 4) | h2);
i += 2;
}
break;
case '=': putchar(':'); putchar(' '); break; // 美化輸出
default: putchar(ch);
}
}
fflush(stdout);
return 0;
}
只需將 MIME Head 改為 text/html,後續 printf 輸出標準 HTML:
printf("Content-Type: text/html\r\n\r\n");
printf("嵌入式 CGI Demo ");
printf("Hello from C CGI!
");
printf("當前時間: %s
", __TIME__);
printf("");
fflush(stdout);
malloc 大塊分配,用靜態緩衝區、棧上陣列;字串操作用 snprintf 防溢出。mod_cgi 每請求 fork 一進程,嵌入式 CPU 弱,避免複雜計算;考慮 FastCGI(持久進程)提升效能。strace -f -p `pidof lighttpd` 追蹤 CGI 啟動;CGI 內用 openlog/syslog 寫系統日誌;或重定向 stderr 到檔案 freopen("/tmp/cgi.log","w",stderr)。system()、popen() 禁用,防命令注入。C 語言 CGI 是嵌入式 Web 介面的基石。掌握 stdin/環境變量/stdout 三元組、URL 解碼、MIME Head 規範,即可構建輕量、高效、安全的設備管理頁面。建議進階學習 FastCGI、cJSON(JSON 生成/解析)、libmicrohttpd(內嵌 HTTP Server)以應對更複雜場景。