
眾多企業級系統(短信網關、企信通、物聯網設備)僅提供 HTTP 接口。Unix/C 後台服務需主動發起 HTTP 請求完成業務交互,構建輕量 HTTP 客戶端成為必備技能。網頁投票器本質即:構造 HTTP GET 請求 → 發送給 Web 服務器 → 解析響應。
https://www.example.com/vote.asp?name=zhangsan&id=1001
│ │ │ │
│ │ │ └─ 查詢參數
│ │ └─ 服務器端腳本路徑
│ └─ 域名/主機地址
└─ 協議標識
投票邏輯通過查詢參數(name=zhangsan)標識目標對象,服務端腳本解析參數後更新數據庫計數。
GET /vote.asp?name=zhangsan HTTP/1.1\r\n
Host: www.example.com\r\n
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\n
Accept: */*\r\n
Accept-Language: zh-cn\r\n
Connection: Keep-Alive\r\n
\r\n
\r\n\r\n 分隔頭與體(GET 無體)HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Content-Length: 190\r\n
Connection: keep-alive\r\n
\r\n
...投票成功...
gethostbyname() 域名 → IPsocket() + connect() 到 80 端口write()/send() 發送完整 HTTP 請求報文recv() 直到連接關閉或讀完 Content-Lengthint sock = socket(AF_INET, SOCK_STREAM, 0);
struct hostent *h = gethostbyname("www.example.com");
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
memcpy(&addr.sin_addr, h->h_addr, h->h_length);
connect(sock, (struct sockaddr*)&addr, sizeof(addr));
char req[1024];
sprintf(req,
"GET /vote.asp?name=zhangsan HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"User-Agent: SimpleHttpClient/1.0\r\n"
"Connection: Close\r\n\r\n");
write(sock, req, strlen(req));
char buf[4096];
int total = 0;
while ((n = recv(sock, buf+total, sizeof(buf)-total, 0)) > 0)
total += n;
buf[total] = '\0';
printf("%s", buf); // 包含頭部和體
close(sock);
| 課題 | 解決方案 |
|---|---|
| 大響應體分片接收 | 循環 recv,根據 Content-Length 或 Chunked 編碼判斷結束 |
| HTTPS 支持 | 集成 OpenSSL,將 socket 升級為 SSL_socket |
| 連接復用 | Connection: Keep-Alive + 連接池管理 |
| 異步非阻塞 | epoll/kqueue + 狀態機解析器 |
| 健壯解析 | 狀態機解析狀態行、頭部、體;處理分包/粘包 |
下一篇將實戰開發完整網頁投票器:命令行參數解析、多線程並發投票、Cookie/Session 維持、反爬蟲策略應對、日誌記錄與異常重試機制。