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

取得網路使用率與連線速度的最佳方案(WMI + IPHLPAPI)

     編輯:關於.NET

需求:取得每張網卡的即時使用率與連線速度。挑戰:虛擬網卡可能同名,傳統 Performance Counter 或 Win32_PerfFormattedData_Tcpip_NetworkInterface 僅靠名稱匹配,無法區分同名卡。任務管理員能正確對應,說明存在更可靠機制。

方案:結合 WMI(取 MAC、Interface Index、Speed)與 IPHLPAPI(取即時收發位元組),透過 Interface Index 精準關聯,相容 Windows 2000 以上系統。

核心資料結構

typedef struct _NetworkUtilization_Map_Element {
    wchar_t MAC[64];
    unsigned int interfaceIndex;
    unsigned __int64 linkSpeed;   // bps
    DWORD preInBytes, preOutBytes; // 上輪累計值
    unsigned int usage;            // 計算出的使用率 %
} NetworkUtilization_Map_Element;

步驟一:WMI 查詢網卡靜態資訊

DWORD InitNetworkAdapterInfo(vector<NetworkUtilization_Map_Element>& ref) {
    // COM 初始化、連線 ROOT\CIMV2、設定 Proxy Blanket
    // 查詢:SELECT MACAddress, InterfaceIndex, Speed FROM Win32_NetworkAdapter WHERE AdapterTypeId = 0
    // 填入 struct 向量
}

關鍵欄位:MACAddress(唯一識別)、InterfaceIndex(對應 IPHLPAPI)、Speed(連線速度 bps)。

步驟二:IPHLPAPI 取得即時收發位元組並計算使用率

DWORD PopulateNetworkUtilization(vector<NetworkUtilization_Map_Element>& ref) {
    PMIB_IFTABLE pIfTable;
    GetIfTable(pIfTable, &dwSize, 0); // 取得 MIB_IFROW 陣列
    for (each row in pIfTable) {
        for (each elem in ref) if (elem.interfaceIndex == row.dwIndex) {
            DWORD inDet = 0, outDet = 0;
            if (elem.preInBytes != 0) { // 非首次呼叫
                // 處理 DWORD 溢位(4GB 歸零)
                inDet = (elem.preInBytes > row.dwInOctets)
                    ? 0xFFFFFFFF - elem.preInBytes + row.dwInOctets
                    : row.dwInOctets - elem.preInBytes;
                outDet = (elem.preOutBytes > row.dwOutOctets)
                    ? 0xFFFFFFFF - elem.preOutBytes + row.dwOutOctets
                    : row.dwOutOctets - elem.preOutBytes;
            }
            elem.preInBytes = row.dwInOctets;
            elem.preOutBytes = row.dwOutOctets;
            unsigned __int64 totalBits = ((unsigned __int64)inDet + outDet) * 8;
            elem.usage = (totalBits > elem.linkSpeed) ? 100 : (unsigned int)(totalBits * 100 / elem.linkSpeed);
            break;
        }
    }
}

公式:Usage % = (ΔIn + ΔOut) * 8 / LinkSpeed * 100。dwInOctets/dwOutOctets 為累計值,故需差分;DWORD 上限 4GB 需溢位處理。

測試主程式

int main() {
    CoInitialize(NULL);
    vector<NetworkUtilization_Map_Element> arr;
    InitNetworkAdapterInfo(arr);
    PopulateNetworkUtilization(arr); // 首次建立基準
    for (int i=0; i<120; i++) {
        PopulateNetworkUtilization(arr);
        for (auto& e : arr) {
            wcout << L"MAC: " << e.MAC << L"\nIndex: " << e.interfaceIndex
                  << L"\nSpeed: " << e.linkSpeed << L"\nUsage: " << e.usage << L"%\n";
        }
        Sleep(1000);
    }
    CoUninitialize();
}

為何不用 MIB_IFROW2?

MIB_IFROW2 含 linkSpeed 欄位,但僅 Vista+ 支援。為相容 Win2000/XP/2003,採 WMI 取 Speed。

優點總結

  • 透過 Interface Index 精準綁定,解決同名網卡無法區分問題
  • 不依賴 Performance Counter,無需管理員權限即可讀取
  • 相容 Windows 2000 至最新版本
  • 自動處理計數器溢位,長時間監控不失真
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved