需求:取得每張網卡的即時使用率與連線速度。挑戰:虛擬網卡可能同名,傳統 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;
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)。
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 含 linkSpeed 欄位,但僅 Vista+ 支援。為相容 Win2000/XP/2003,採 WMI 取 Speed。
Interface Index 精準綁定,解決同名網卡無法區分問題