IOCP 是 Windows 平台最高效的伺服器網路模型。核心流程如下:
CreateIoCompletionPort。GetQueuedCompletionStatus 等待 I/O 完成通知。AcceptEx (非阻塞) 接受連線,並將新 Socket 關聯至完成端口。WSARecv/WSASend,由核心驅動執行實際傳輸。
AcceptEx 為非阻塞,可同時投遞多個接受請求。若預期客戶端連線即發送資料 (如 HTTP),可在 AcceptEx 中預投遞接收緩衝區,合併連線建立與首包接收,減少一次系統呼叫。
頻繁連線會導致大量小記憶體區塊分配/釋放。Lookaside List 以單向鏈表預先分配固定大小區塊:
此技術源自 Windows 核心 (IRP、MDL 分配),大幅降低記憶體管理開銷。
使用 AcceptEx 預投遞緩衝區時,若客戶端僅連線不傳資料,該請求永不完成,佔用資源。解決方案:定期輪詢 getsockopt(SO_CONNECT_TIME),關閉超過閾值且無資料交換的連線。
避免一次投遞過多 AcceptEx 造成效能抖動。利用 WSAEventSelect 綁定 FD_ACCEPT 事件至 Event 物件,當投遞池耗盡時 WaitForSingleObject 觸發,補充新的 AcceptEx 請求。
封裝目標:開發者僅需繼承基類並覆寫兩個虛擬函式 HandleData (資料處理) 與 DataAction (業務動作),即可快速構建各類伺服器。
class MyEchoServer : public CompletionPortModel
{
protected:
virtual void HandleData(PER_HANDLE_DATA* pHandleData, PER_IO_DATA* pIoData) override
{
// 直接回傳收到的資料
PostSend(pHandleData, pIoData->Buffer, pIoData->BytesTransferred);
}
virtual void DataAction(PER_HANDLE_DATA* pHandleData) override {}
};
void main()
{
MyEchoServer server;
server.Init();
server.AllocEventMessage();
if (!server.PostAcceptEx()) return;
server.ThreadLoop(); // 進入工作執行緒循環
}
HandleData 耗時長,會拖垮整個完成端口,建議將重邏輯派發至獨立執行緒池。參考 Platform SDK 範例、Tmndecoder (Karl Lillevold) 及 h.263 快速編碼庫 (Roalt Aalmoes)。完整原始碼與 Demo 可下載。