通過原始 Socket 手工構造 HTTP POST 請求,實現網頁表單登錄。適用於無驗證碼、基於 Cookie 的簡單認證場景。演示環境:目標 IP 222.73.24.32,帳號 lzh_2,密碼 123456789。
POST 路徑、Headers、Body 格式。Host、Content-Type、Content-Length、Cookie、User-Agent 等)、空行、Body(application/x-www-form-urlencoded)。send() 發送請求,recv() 讀取響應,判斷登錄成功標識。#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <cstring>
#pragma comment(lib, "ws2_32.lib")
#define MAX_BUF 20480
int main() {
WSADATA wsa; WSAStartup(MAKEWORD(2,1), &wsa);
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serv{};
serv.sin_family = AF_INET;
serv.sin_port = htons(80);
serv.sin_addr.S_un.S_addr = inet_addr("222.73.24.32");
connect(s, (sockaddr*)&serv, sizeof(serv));
char sndBuf[MAX_BUF] = {}, rcvBuf[MAX_BUF] = {};
// 構造 HTTP POST 請求(注意 \r\n 換行)
strcat(sndBuf, "POST /inc/Check.asp HTTP/1.1\r\n");
strcat(sndBuf, "Host: user.exam8.com\r\n");
strcat(sndBuf, "Content-Type: application/x-www-form-urlencoded\r\n");
strcat(sndBuf, "Content-Length: 61\r\n");
strcat(sndBuf, "Cookie: Hm_lvt_...=...; ASPSESSIONID...=...\r\n");
strcat(sndBuf, "User-Agent: Mozilla/4.0 ...\r\n");
strcat(sndBuf, "Connection: Keep-Alive\r\n");
strcat(sndBuf, "\r\n"); // 必須有空行分隔 Header 和 Body
strcat(sndBuf, "Action=login&LoginUserName=lzh_2&LoginUserPassword=123456789&");
send(s, sndBuf, strlen(sndBuf), 0);
int len = recv(s, rcvBuf, MAX_BUF-1, 0);
rcvBuf[len] = '\0';
std::cout << "Response:\n" << rcvBuf << std::endl;
closesocket(s); WSACleanup();
return 0;
}
CRLF 結尾,Header 結束後額外一個 CRLF(即空行)。& 等特殊字符。URL Encode(空格→+ 或 %20,特殊字符→%XX)。登錄成功:HTTP/1.1 200 OK ... "login success" / 重定向到主頁 / 設置新 Cookie 失敗:HTTP/1.1 200 OK ... "用戶名或密碼錯誤" / 返回登錄頁
生產環境**強烈建議**使用成熟庫:
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ...) 自動處理編碼、重定向、Cookie、HTTPS、Keep-Alive。手工 Socket 發送 POST 是理解 HTTP 協議的絕佳練習,但**生產代碼請勿直接使用**。掌握請求構造細節(Header、Body、編碼、換行),有助於調試網絡問題、編寫爬蟲、理解 Web 安全原理。現代 C++ 網絡開發首選 libcurl 或 cpp-httplib。