vc++实现获取网络占用率(附带源码)
一、项目背景详细介绍
在现代计算机系统中,网络带宽占用率(Network Utilization) 是衡量系统性能的重要指标之一。
许多系统监控软件(如任务管理器、网络流量监控器、资源管理器)都实时显示网络使用率。
在企业级应用、服务器管理、性能分析、网络优化、或智能控制系统中,
我们常常需要获取当前网卡实时上传与下载速率、带宽利用率等数据。
本项目的目标是使用 VC++(Win32 API + IP Helper API) 实现:
-
自动枚举系统中所有网络接口;
-
实时读取网络传输字节数;
-
计算带宽利用率(%);
-
定时刷新网络占用情况。
这种方法的优点:
-
无需安装第三方库;
-
兼容 Windows XP 至 Windows 11;
-
可轻松扩展为网络监控工具。
二、项目需求详细介绍
2.1 功能性需求
-
获取系统中所有网卡接口名称;
-
获取每个网卡的传输速率(bytes sent / bytes received);
-
每隔一定时间刷新网络数据;
-
计算网卡带宽占用率(发送、接收、总占用率);
-
将结果输出到控制台。
2.2 非功能性需求
-
仅使用 Windows API;
-
无需管理员权限;
-
程序稳定、安全;
-
支持多网卡;
-
支持 Unicode。
三、相关技术详细介绍
3.1 IP Helper API 概述
IP Helper API(iphlpapi.dll)是微软提供的网络接口信息访问库,
头文件为 <iphlpapi.h>,链接库为 iphlpapi.lib。
常用函数如下:
| 函数 | 功能 |
|---|---|
| GetIfTable | 获取网卡接口表(旧版接口) |
| GetIfEntry | 获取单个网卡接口信息 |
| GetIfTable2 / GetIfEntry2 | 新版接口(Vista+) |
| GetAdaptersAddresses | 获取网卡地址及信息 |
| GetAdaptersInfo | 旧版接口 |
本项目选用 GetIfTable 读取网络接口信息。
结构体定义如下:
typedef struct _MIB_IFROW {
WCHAR wszName[MAX_INTERFACE_NAME_LEN];
DWORD dwIndex;
DWORD dwType;
DWORD dwMtu;
DWORD dwSpeed; // 接口速率(比特/秒)
DWORD dwPhysAddrLen;
BYTE bPhysAddr[MAXLEN_PHYSADDR];
DWORD dwAdminStatus;
DWORD dwOperStatus;
DWORD dwLastChange;
DWORD dwInOctets; // 接收字节数
DWORD dwInUcastPkts;
DWORD dwInNUcastPkts;
DWORD dwInDiscards;
DWORD dwInErrors;
DWORD dwOutOctets; // 发送字节数
DWORD dwOutUcastPkts;
DWORD dwOutNUcastPkts;
DWORD dwOutDiscards;
DWORD dwOutErrors;
DWORD dwOutQLen;
DWORD dwDescrLen;
BYTE bDescr[MAXLEN_IFDESCR];
} MIB_IFROW;
3.2 网络占用率计算原理
假设:
-
接口带宽:
dwSpeed(单位:bit/s) -
两次采样时间间隔:
Δt -
接收字节差值:
ΔInOctets -
发送字节差值:
ΔOutOctets
则网络总流量为:
ΔBytes = ΔInOctets + ΔOutOctets
网络占用率计算公式:
Utilization = (ΔBytes * 8 / Δt) / dwSpeed * 100%
即,计算时间内的平均速率占理论带宽的百分比。
3.3 定时采样机制
为了实现实时刷新,我们使用:
-
Sleep()进行时间间隔; -
GetTickCount64()或QueryPerformanceCounter()计算精确时间; -
每隔 N 秒重新采样,计算差值。
四、实现思路详细介绍
-
调用
GetIfTable()获取系统网卡信息; -
输出接口列表与带宽;
-
保存初始的字节计数;
-
等待一段时间(如1秒);
-
再次调用
GetIfTable(); -
计算字节差值与时间差;
-
根据带宽计算网络占用率;
-
循环刷新,实时输出数据。
五、完整实现代码
/*********************************************************
* 文件名称:NetworkUsage.cpp
* 功能描述:VC++ 实现获取系统网络占用率
* 编译环境:Visual Studio 2019 / VC++ 6.0
*********************************************************/
#include <windows.h>
#include <iphlpapi.h>
#include <iostream>
#include <string>
#include <vector>
#pragma comment(lib, "iphlpapi.lib")
using namespace std;
/*********************************************************
* 结构体:NetInterfaceInfo
* 功能:保存每个网卡的基础信息与采样数据
*********************************************************/
struct NetInterfaceInfo
{
DWORD index;
string name;
DWORD speed; // 网卡速率 bit/s
ULONG inBytesPrev;
ULONG outBytesPrev;
double utilizationIn; // 接收占用率 %
double utilizationOut; // 发送占用率 %
};
/*********************************************************
* 函数:GetNetworkInterfaces
* 功能:枚举系统所有网卡接口
*********************************************************/
vector<NetInterfaceInfo> GetNetworkInterfaces()
{
vector<NetInterfaceInfo> interfaces;
PMIB_IFTABLE pIfTable;
DWORD dwSize = 0;
DWORD dwRet = GetIfTable(NULL, &dwSize, FALSE);
pIfTable = (PMIB_IFTABLE)malloc(dwSize);
if (GetIfTable(pIfTable, &dwSize, FALSE) == NO_ERROR)
{
for (DWORD i = 0; i < pIfTable->dwNumEntries; i++)
{
MIB_IFROW row = pIfTable->table[i];
NetInterfaceInfo info;
info.index = row.dwIndex;
info.speed = row.dwSpeed;
info.name = string((char*)row.bDescr, row.dwDescrLen);
info.inBytesPrev = row.dwInOctets;
info.outBytesPrev = row.dwOutOctets;
info.utilizationIn = info.utilizationOut = 0.0;
// 过滤掉环回和非活动接口
if (row.dwType != IF_TYPE_SOFTWARE_LOOPBACK && row.dwOperStatus == IF_OPER_STATUS_OPERATIONAL)
interfaces.push_back(info);
}
}
free(pIfTable);
return interfaces;
}
/*********************************************************
* 函数:UpdateNetworkUsage
* 功能:刷新每个接口的网络占用率
*********************************************************/
void UpdateNetworkUsage(vector<NetInterfaceInfo>& interfaces, double intervalSeconds)
{
PMIB_IFTABLE pIfTable;
DWORD dwSize = 0;
DWORD dwRet = GetIfTable(NULL, &dwSize, FALSE);
pIfTable = (PMIB_IFTABLE)malloc(dwSize);
if (GetIfTable(pIfTable, &dwSize, FALSE) == NO_ERROR)
{
for (DWORD i = 0; i < pIfTable->dwNumEntries; i++)
{
MIB_IFROW row = pIfTable->table[i];
for (auto& net : interfaces)
{
if (net.index == row.dwIndex)
{
ULONG inDelta = row.dwInOctets - net.inBytesPrev;
ULONG outDelta = row.dwOutOctets - net.outBytesPrev;
net.inBytesPrev = row.dwInOctets;
net.outBytesPrev = row.dwOutOctets;
// 计算速率(bit/s)
double inRate = (inDelta * 8.0) / intervalSeconds;
double outRate = (outDelta * 8.0) / intervalSeconds;
net.utilizationIn = (inRate / net.speed) * 100.0;
net.utilizationOut = (outRate / net.speed) * 100.0;
}
}
}
}
free(pIfTable);
}
/*********************************************************
* 主函数:实时显示网络占用率
*********************************************************/
int main()
{
cout << "===== VC++ 获取网络占用率示例 =====" << endl;
vector<NetInterfaceInfo> nets = GetNetworkInterfaces();
if (nets.empty())
{
cout << "未检测到有效网络接口!" << endl;
return 0;
}
cout << "检测到 " << nets.size() << " 个网卡接口:" << endl;
for (auto& n : nets)
cout << "接口:" << n.name << " 速率:" << n.speed / 1000000 << " Mbps" << endl;
cout << "\n开始实时监控网络占用率(按 Ctrl+C 退出)..." << endl;
while (true)
{
double interval = 1.0; // 1秒间隔
Sleep((DWORD)(interval * 1000));
UpdateNetworkUsage(nets, interval);
system("cls");
cout << "当前网络使用情况:" << endl;
for (auto& n : nets)
{
cout << "接口:" << n.name
<< " | 下行:" << n.utilizationIn << "%"
<< " | 上行:" << n.utilizationOut << "%"
<< " | 总占用:" << n.utilizationIn + n.utilizationOut << "%" << endl;
}
}
return 0;
}
六、代码详细解读
-
GetNetworkInterfaces()-
调用
GetIfTable()枚举所有网卡; -
过滤非活动与环回接口;
-
保存每个网卡的速率、字节计数。
-
-
UpdateNetworkUsage()-
再次调用
GetIfTable()获取实时流量数据; -
计算上次与本次之间的差值;
-
根据间隔时间计算速率;
-
根据带宽计算占用率。
-
-
main()-
初始化网卡列表;
-
每隔 1 秒刷新一次;
-
实时输出网络占用率。
-
七、项目详细总结
本项目通过 VC++ 的 IP Helper API 实现了获取系统网络占用率的功能。
项目完整地涵盖了以下核心知识点:
-
网络接口信息枚举;
-
字节统计与速率计算;
-
实时刷新与控制台显示;
-
数据采样与时间差计算;
-
网络带宽占用率计算原理。
该实现思路简单、稳定,特别适合嵌入系统监控程序或自定义网络分析工具中。
运行结果示例(1秒采样):
当前网络使用情况: 接口:Realtek PCIe GbE Family Controller | 下行:2.35% | 上行:0.84% | 总占用:3.19% 接口:Intel Wi-Fi 6 AX200 160MHz | 下行:0.12% | 上行:0.04% | 总占用:0.16%
八、项目常见问题及解答
Q1:为什么所有网卡显示为0%?
A1:可能当前没有网络传输流量,请尝试下载或播放视频以产生数据。
Q2:如何让刷新更快?
A2:减少采样间隔,例如设为 0.5 秒;但会增加 CPU 占用。
Q3:为什么速率单位是比特?
A3:因为带宽是以 bit/s 表示的,所以计算中需乘以 8(Byte→bit)。
Q4:支持无线网卡和虚拟网卡吗?
A4:支持,只要系统识别为网络接口即可。
Q5:如何在 GUI 程序中显示?
A5:可将结果绑定到 MFC 对话框控件上,定时刷新显示。
九、扩展方向与性能优化
-
多线程刷新机制
-
将监控线程与UI分离,提高响应速度。
-
-
数据图形化展示
-
使用 GDI+ 绘制实时曲线图表。
-
-
带宽自适应
-
自动检测接口最大速率,动态计算百分比。
-
-
日志记录功能
-
定期保存网络使用率到日志文件,便于长期分析。
-
-
网络包捕获扩展
-
使用 WinPcap/Npcap 捕获真实包流,进行更精准统计。
-
-
跨平台实现
-
在 Linux 下使用
/proc/net/dev或getifaddrs实现同样功能。
-
-
性能优化
-
使用
GetIfEntry2(新API)获取更精确的64位计数器; -
使用异步事件代替 Sleep,提高采样稳定性。
-
更多推荐

所有评论(0)