首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

Windows Socket API 實戰經驗總結:從 WSAStartup 到連線管理

     編輯:關於C++

前言:跨平台網路程式設計的踩坑記錄

本文彙整筆者在 Windows 與 HP-UX 雙平台網路程式開發的實戰經驗,聚焦 **同步阻塞模式** 下核心 Socket API 的行為細節、錯誤處理陷阱與最佳實踐,供開發者參考避坑。

核心 API 深度解析

1. WSAStartup — 版本協商與 DLL 綁定

WORD wVersion = MAKEWORD(2, 1); // 要求 2.1 版
WSADATA wsaData;
int err = WSAStartup(wVersion, &wsaData);
// 成功回傳 0,wsaData 輸出實際版本、廠商資訊、最大 Socket 數等
  • 進程空間載入對應版本 Winsock DLL (ws2_32.dll)
  • **必須配對呼叫** WSACleanup 釋放資源

2. WSACleanup — 解除綁定與資源釋放

應用程式結束前呼叫,減少參考計數,歸零時卸載 DLL。

3. socket — 建立通訊端點

struct protoent *ppe = getprotobyname("tcp");
SOCKET s = socket(PF_INET, SOCK_STREAM, ppe->p_proto);
  • 回傳 **Socket 描述符** (整數),進程內部索引 Kernel Socket 物件
  • 每進程維護描述符表,Kernel 物件含參考計數

4. closesocket — 關閉與參考計數機制

  • 參考計數 = 1:移除描述符表項、**釋放 Kernel 物件**
  • 參考計數 > 1:僅移除表項、**參考計數 -1**,物件存續
  • 成功回傳 0,失敗 SOCKET_ERROR

5. send — 發送緩衝區複製語義與阻塞行為

關鍵認知:send **只負責將使用者緩衝區資料複製至 Kernel 發送緩衝區**,而非傳送至網路。

  • 若資料長度 > 發送緩衝區總大小 → 立即失敗 SOCKET_ERROR
  • 若資料長度 > 發送緩衝區**剩餘**空間 → **阻塞等待** 協定堆疊騰出空間
  • 非阻塞模式下剩餘空間不足 → 失敗 WSAEWOULDBLOCK
  • 回傳成功 **不保證** 對端已收到,僅表示進入發送佇列
  • 後續任一 Socket API 呼叫前,皆會隱性等待發送緩衝區排空;若網路斷開,該 API 回傳 SOCKET_ERROR

6. recv — 接收緩衝區複製語義

  • 先等待發送緩衝區排空 (同 send)
  • 檢查接收緩衝區:無資料或協定正在接收 → **阻塞等待**
  • 資料就緒 → **複製至使用者緩衝區**,回傳複製位元組數
  • 對端正常關閉 (FIN) → 回傳 0
  • 網路斷開 (RST) → 回傳 SOCKET_ERROR (Windows) / 收到 SIGPIPE (Unix 預設終止進程)

7. bind — 綁定本地位址與 Port

  • 伺服器**必須**綁定固定 IP/Port (如 INADDR_ANY + htons(8888))
  • 用戶端通常**不需**呼叫,由 connect 隱性綁定臨時 Port
  • sockaddr_in 結構:sin_family=AF_INET, sin_port, sin_addr.s_addr

8. listen — 進入被動監聽狀態

  • 僅適用 SOCK_STREAM
  • backlog:未完成三向交握連線佇列上限 (系統限制)

9. accept — 接受連線並建立新 Socket

  • 從監聽 Socket 佇列取出首個已完成連線
  • 回傳**新 Socket 描述符**,用於後續收發;原監聽 Socket 繼續監聽
  • 可透過 addr/addrlen 取得客戶端位址

10. connect — 主動發起連線

  • 客戶端呼叫,觸發三向交握
  • 阻塞直到連線成功、失敗或逾時
  • 非阻塞模式下立即回傳 WSAEWOULDBLOCK,需用 select 監控寫就緒判斷完成

跨平台差異提醒

場景WindowsUnix/Linux
send/recv 期間網路斷開下一個 Socket API 回傳 SOCKET_ERROR進程收到 SIGPIPE,預設終止
非阻塞 connectWSAEWOULDBLOCK + select 監控寫集合EINPROGRESS + select/poll 監控寫集合
關閉 Socketclosesocketclose

最佳實踐清單

  1. 啟動時檢查 WSAStartup 回傳值
  2. 所有 Socket API 檢查回傳值,失敗呼叫 WSAGetLastError()
  3. 發送大量資料時實作分塊重試邏輯 (處理 WSAEWOULDBLOCK)
  4. 接收端實作封包邊界處理 (長度前綴或分隔符)
  5. 優雅關閉:shutdown(s, SD_SEND) → 循環 recv 至 0 → closesocket
  6. 多執行緒/IOCP 架構下注意 Socket 物件生命週期管理
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved