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

Winsock 完成端口 (IOCP) 模型 C++ 封裝類別設計與效能優化

     編輯:VC++

完成端口模型核心流程

IOCP 是 Windows 平台最高效的伺服器網路模型。核心流程如下:

  1. 建立完成端口 CreateIoCompletionPort。
  2. 啟動工作執行緒池,循環呼叫 GetQueuedCompletionStatus 等待 I/O 完成通知。
  3. 主執行緒使用 AcceptEx (非阻塞) 接受連線,並將新 Socket 關聯至完成端口。
  4. 發起非同步 WSARecv/WSASend,由核心驅動執行實際傳輸。
  5. 核心完成 I/O 後將結果排入完成端口佇列。
  6. 工作執行緒取出結果處理業務邏輯,再發起下一次非同步 I/O。

IOCP 處理流程圖

關鍵效能優化策略

1. AcceptEx 取代 Accept

AcceptEx 為非阻塞,可同時投遞多個接受請求。若預期客戶端連線即發送資料 (如 HTTP),可在 AcceptEx 中預投遞接收緩衝區,合併連線建立與首包接收,減少一次系統呼叫。

2. Lookaside List (旁路列表) 記憶體管理

頻繁連線會導致大量小記憶體區塊分配/釋放。Lookaside List 以單向鏈表預先分配固定大小區塊:

  • 需求時:鏈表非空則取出節點,否則新分配。
  • 釋放時:不還給堆疊,插回鏈表供下次復用。

此技術源自 Windows 核心 (IRP、MDL 分配),大幅降低記憶體管理開銷。

3. 連線逾時檢測 (SO_CONNECT_TIME)

使用 AcceptEx 預投遞緩衝區時,若客戶端僅連線不傳資料,該請求永不完成,佔用資源。解決方案:定期輪詢 getsockopt(SO_CONNECT_TIME),關閉超過閾值且無資料交換的連線。

4. 動態調整 AcceptEx 投遞數量

避免一次投遞過多 AcceptEx 造成效能抖動。利用 WSAEventSelect 綁定 FD_ACCEPT 事件至 Event 物件,當投遞池耗盡時 WaitForSingleObject 觸發,補充新的 AcceptEx 請求。

通用封裝類別設計

封裝目標:開發者僅需繼承基類並覆寫兩個虛擬函式 HandleData (資料處理) 與 DataAction (業務動作),即可快速構建各類伺服器。

最小化使用範例 (Echo Server)

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(); // 進入工作執行緒循環
}

測試結果與已知限制

  • 單機測試:客戶端 3000+ 連線循環收發,伺服器穩定運行。
  • 未支援多處理器擴展:理想應建立 CPU 核心數 × 2 條工作執行緒。
  • 未處理工作執行緒阻塞:若 HandleData 耗時長,會拖垮整個完成端口,建議將重邏輯派發至獨立執行緒池。

致謝與參考

參考 Platform SDK 範例、Tmndecoder (Karl Lillevold) 及 h.263 快速編碼庫 (Roalt Aalmoes)。完整原始碼與 Demo 可下載。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved