在 Windows 平台進行 Socket 編程,**任何 Winsock API 調用前**必須先調用 `WSAStartup`。它的核心作用是:
int WSAStartup(
WORD wVersionRequested, // 請求版本:高字節=次版本,低字節=主版本
LPWSADATA lpWSAData // 輸出:實際版本詳情
);
// 期望版本 2.2 → 低字節 2(主版本),高字節 2(次版本)
WORD version = MAKEWORD(2, 2); // 等同於 0x0202
// 常見版本對照
// MAKEWORD(1, 1) = 0x0101 → Winsock 1.1 (老舊)
// MAKEWORD(2, 0) = 0x0002 → Winsock 2.0
// MAKEWORD(2, 2) = 0x0202 → Winsock 2.2 (標準推薦)
struct WSADATA {
WORD wVersion; // 實際支持的最高版本(低字節主版本)
WORD wHighVersion; // 系統支持的最高版本
char szDescription[WSADESCRIPTION_LEN+1]; // 廠商描述
char szSystemStatus[WSASYS_STATUS_LEN+1]; // 系統狀態
unsigned short iMaxSockets; // 最大 Socket 數(通常無限制)
unsigned short iMaxUdpDg; // 最大 UDP 數據報大小
char FAR *lpVendorInfo; // 廠商特定信息指針
};
#include
#include // 現代 API 需包含
#pragma comment(lib, "ws2_32.lib")
bool InitWinsock()
{
WSADATA wsaData;
// 請求 2.2 版本
int ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (ret != 0) {
cerr << "WSAStartup failed: " << ret << endl;
return false;
}
// 確認系統支持 2.2
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
cerr << "Winsock 2.2 not supported. Highest: "
<< (int)LOBYTE(wsaData.wVersion) << "." << (int)HIBYTE(wsaData.wVersion) << endl;
WSACleanup();
return false;
}
return true;
}
int main() {
if (!InitWinsock()) return 1;
// ... 正常 Socket 編程 ...
WSACleanup(); // 程序結束前必須調用,釋放資源
return 0;
}
| 請求版本 | 系統最高版本 | wVersion (實際) | wHighVersion | 結果 |
|---|---|---|---|---|
| 2.2 | 2.2 | 2.2 | 2.2 | 成功,完全匹配 |
| 2.2 | 2.0 | 2.0 | 2.0 | 成功,返回較低版本,應用需兼容 |
| 1.1 | 2.2 | 1.1 | 2.2 | 成功,但僅能用 1.1 功能 |
| 3.0 | 2.2 | 0 | 2.2 | 失敗,返回 0,不支持 |
核心原則:系統返回 **不超過請求版本的最高可用版本**。應用應檢查 `wVersion` 是否滿足最低需求。
class WinsockGuard {
bool initialized = false;
public:
WinsockGuard(WORD version = MAKEWORD(2,2)) {
WSADATA data;
if (WSAStartup(version, &data) == 0) {
// 可選:檢查版本
initialized = true;
}
}
~WinsockGuard() {
if (initialized) WSACleanup();
}
// 禁止拷貝,允許移動
WinsockGuard(const WinsockGuard&) = delete;
WinsockGuard& operator=(const WinsockGuard&) = delete;
WinsockGuard(WinsockGuard&& other) noexcept : initialized(other.initialized) {
other.initialized = false;
}
explicit operator bool() const { return initialized; }
};
// 使用:main 開頭聲明一個實例,作用域結束自動清理
int main() {
WinsockGuard guard;
if (!guard) return 1;
// 安全進行 Socket 編程...
}
核心洞見: `WSAStartup` 不是「啟動網絡」,而是「初始化進程級 Winsock 環境」。理解版本協商機制、RAII 管理生命週期、區分進程級與線程級操作,是 Windows 網絡編程穩健的基石。