【操作系统08】获取网络速率、网络占用率
原创作者:郑同学的笔记原文链接:https://zhengjunxue.blog.csdn.net/article/details/137550822。
【操作系统08】获取网络占用率
原创作者:郑同学的笔记
原文链接:https://zhengjunxue.blog.csdn.net/article/details/137550822
一、网络速率和网络占用率
在网络术语中,网络速率和网络占用率是两个不同的概念:
1、网络速率(Network Rate):
-
定义:网络速率通常指的是网络连接的最大数据传输速度,即单位时间内网络可以传输的数据量。它的计量单位通常是比特每秒(bits per second,bps),常见的还有千比特每秒(Kbps)、兆比特每秒(Mbps)和吉比特每秒(Gbps)等。
-
实例:如果你的互联网服务提供商承诺提供100 Mbps的下载速率,这意味着理想情况下,你的网络连接理论上可以在一秒内传输最多100兆比特的数据。
网络速率 = 单位时间网络流量 / 时间
2、网络占用率(Network Utilization):
-
定义:网络占用率则指的是在某一时间点或时间段内,网络的实际传输数据量占网络最大传输能力的比例。它是对网络资源被使用的程度的度量,通常以百分比形式表示。
-
实例:如果网络的最大带宽为1 Gbps,而目前实际传输的数据量为500 Mbps,则网络占用率为50%。
网络占用率 = 网络速率/网络带宽
所以,你想计算网络占用率,只需要把我们本篇计算的网络速率计算出来,然后除以你的网络带宽,就是网络占用率了。
二、计算网络速率的方法_windows
1、windows
-
PDH(Performance Data Helper):
PDH 是 Windows 中用于收集性能计数器数据的API。通过 PDH,你可以编程方式访问系统性能数据,包括网络接口的传输速率。你可以使用 PDH API 来编写自己的应用程序或脚本来监视网络速率。
使用 PDH API,你可以编写一些自定义的代码来查询性能计数器数据,包括网络接口的传输速率。这个方法需要一定的编程技能,但提供了更灵活和定制化的方式来监视网络性能。 -
IP Helper:
IP Helper 是一个 Windows API,提供了许多函数来查询和管理网络配置信息。虽然 IP Helper 主要用于获取和设置 IP 地址、路由表、网络接口信息等,但也可以用于监视网络接口的状态和性能。
通过 IP Helper,你可以编写自己的程序来查询网络接口的信息,包括当前的连接状态、速率等。虽然 IP Helper 不像 PDH 那样专门用于性能监视,但它可以提供一些相关的网络信息。
2、PDH调用接口流程:
- 在计算网络速率时,pdh(Performance Data Helper)是一个Windows Performance Counters(性能计数器)的API,用于访问和操作性能计数器数据,包括但不限于处理器利用率、内存使用情况以及网络接口的统计信息。
- 初始化 PDH 查询对象:PdhOpenQuery();
- 添加网络接口速率计数器:PdhAddCounter();
- 收集计数器数据: PdhCollectQueryData();
- 等待时间,如sleep,比如1s
- 再次,收集计数器数据: PdhCollectQueryData();
- 获取计数器的当前值(即速率: 这里的单位是字节/秒 (Bytes/second) ):PdhGetFormattedCounterValue();
- 计算并输出速率(转换为适当的单位,如 Kbps、Mbps):
#include <pdh.h>
#include <pdhmsg.h>
#pragma comment(lib, "pdh.lib")
// 示例代码简化版,不完整,仅为示意
void getNetworkUsage()
{
PDH_HQUERY queryHandle;
PDH_HCOUNTER counterHandle;
PDH_FMT_COUNTERVALUE counterValue;
// 创建查询句柄
PdhOpenQuery(NULL, NULL, &queryHandle);
// 添加网络接口计数器,例如“\\Network Interface(*)\\Bytes Sent/sec”
PdhAddCounter(queryHandle, "\\Network Interface(*)\\Bytes Sent/sec", NULL, &counterHandle);
// 更新计数器值
PdhCollectQueryData(queryHandle);
// 等待合适的时间间隔后再次收集数据(例如Sleep函数)
Sleep(1000);
// 收集第二次数据
PdhCollectQueryData(queryHandle);
// 获取速率值
PdhGetFormattedCounterValue(counterHandle, PDH_FMT_DOUBLE, NULL, &counterValue);
double sentRate = counterValue.doubleValue;
// 类似地,获取接收速率(例如:“\\Network Interface(*)\\Bytes Received/sec”)
// 关闭查询句柄
PdhCloseQuery(queryHandle);
// 根据实际情况计算网络占用率,例如:(sentRate + receivedRate) / 2
// 此处的计算取决于具体的定义和需求
}
3、使用IP Helper库
使用使用IP Helper库需要统计,太麻烦了,我们还是采用pdh来实现。
// 或者使用IP Helper库
#include <iphlpapi.h>
#include <winsock2.h>
#include <ws2tcpip.h>
void getNetworkUsageIPHLPAPI()
{
MIB_IFTABLE* pIfTable = NULL;
ULONG dwSize = 0;
// 获取所需的缓冲区大小
GetIfTable(pIfTable, &dwSize, FALSE);
pIfTable = (MIB_IFTABLE*)malloc(dwSize);
// 获取网络接口表
if (GetIfTable(pIfTable, &dwSize, TRUE) == NO_ERROR)
{
for (DWORD i = 0; i < pIfTable->dwNumEntries; ++i)
{
MIB_IFROW ifRow = pIfTable->table[i];
ULONG64 bytesSent = ifRow.dwOutOctets;
ULONG64 bytesReceived = ifRow.dwInOctets;
// 计算速率(假设有两次采样,可以根据时间间隔来计算)
// ...
}
free(pIfTable);
}
}
三、计算网络速率的方法——linux
Linux环境:
原理: 在Linux中,可以读取 /proc/net/dev 文件获取网络接口的统计信息。
接口与参数:
Cpp
#include <fstream>
#include <iostream>
#include <regex>
#include <chrono>
void getNetworkUsageLinux()
{
using namespace std::chrono_literals;
auto start = std::chrono::steady_clock::now();
// 等待合适的时间间隔
std::this_thread::sleep_for(1s);
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(end - start).count();
std::ifstream ifs("/proc/net/dev");
std::string line;
std::smatch match;
// 查找指定接口,例如 "eth0"
std::string interfaceName = "eth0";
while (std::getline(ifs, line))
{
if (std::regex_search(line, match, std::regex(interfaceName + ":")))
{
std::istringstream iss(line);
std::string discard;
iss >> discard >> discard >> discard; // 跳过前三列
uint64_t prevRecv, prevSend, currRecv, currSend;
iss >> prevRecv >> prevSend; // 读取前一时刻的接收和发送字节数
// 休息一段时间后重新读取
ifs.clear();
ifs.seekg(0);
std::getline(ifs, line);
std::istringstream iss2(line);
iss2 >> discard >> discard >> discard;
iss2 >> currRecv >> currSend; // 读取当前时刻的接收和发送字节数
// 计算速率(假设字节/秒)
double recvRate = (currRecv - prevRecv) / static_cast<double>(duration);
double sendRate = (currSend - prevSend) / static_cast<double>(duration);
// 根据实际情况计算网络占用率
// ...
}
}
}
四、使用pdh的完整demo
#include <iostream>
#include <pdh.h>
#include <pdhmsg.h>
#pragma comment(lib, "pdh.lib")
using namespace std;
// 示例代码简化版,
int getNetworkUsage(double &sentRate,double &receivedRate)
{
// 创建查询句柄
PDH_HQUERY queryHandle = NULL; //查询句柄
PDH_STATUS pdhStatus = PdhOpenQuery(NULL, 0, &queryHandle);
if (ERROR_SUCCESS != pdhStatus)
{
cout << "Failed to open query.\n";
return -1;
}
//实际网络接口名称,如 "Network Interface(Intel[R] Wi-Fi 6E AX211 160MHz)",具体可以手动建立一个性能计数器,看下名字
// 发送网络的性能计数器路径、接收网络的性能计数器路径
LPCSTR sentPath = "\\Network Interface(Intel[R] Wi-Fi 6E AX211 160MHz)\\Bytes Sent/sec";
LPCSTR recvPath = "\\Network Interface(Intel[R] Wi-Fi 6E AX211 160MHz)\\Bytes Received/sec";
//添加到查询的计数器的句柄。 可能需要在后续调用中引用此句柄。
PDH_HCOUNTER sentCounterHandle = NULL;
PDH_HCOUNTER receivedCounterHandle = NULL;
// 添加发送字节计数器
pdhStatus = PdhAddCounter(queryHandle, sentPath, NULL, &sentCounterHandle);
if (ERROR_SUCCESS != pdhStatus)
{
cout << "Error adding Bytes Sent/sec counter.\n";
goto cleanup;
return -1;
}
// 添加接收字节计数器
pdhStatus = PdhAddCounter(queryHandle, recvPath, NULL, &receivedCounterHandle);
if (ERROR_SUCCESS != pdhStatus)
{
cout << "Error adding Bytes Received/sec counter.\n";
return -1;
}
int flag = 0;
while(1)
{
if (flag == 0)
{
// 第一次,更新计数器值
pdhStatus = PdhCollectQueryData(queryHandle);
if (ERROR_SUCCESS != pdhStatus)
{
cout << "Error collecting data.\n";
goto cleanup;
return -1;
}
flag++;
}
// 等待合适的时间间隔后再次收集数据(例如Sleep函数)
Sleep(1000);
// 假设在此处等待一段时间,然后再次收集数据以得到差值
// 收集第二次数据
pdhStatus = PdhCollectQueryData(queryHandle);
if (ERROR_SUCCESS != pdhStatus)
{
cout << "Error collecting data.\n";
goto cleanup;
return -1;
}
//接收计数器值的 PDH_FMT_COUNTERVALUE 结构
PDH_FMT_COUNTERVALUE sentCounterValue, receivedCounterValue;
// 获取发送速率值
pdhStatus = PdhGetFormattedCounterValue(sentCounterHandle, PDH_FMT_DOUBLE, NULL, &sentCounterValue);
if (ERROR_SUCCESS != pdhStatus)
{
cout << "Error getting Bytes sent/sec value.\n";
goto cleanup;
return -1;
}
/*double */sentRate = sentCounterValue.doubleValue;// 这里的单位是字节/秒 (Bytes/second)
printf("Bytes sent/sec: %lf\n", sentRate);
// 获取接收速率值
pdhStatus = PdhGetFormattedCounterValue(receivedCounterHandle, PDH_FMT_DOUBLE, NULL, &receivedCounterValue);
if (ERROR_SUCCESS != pdhStatus)
{
cout << "Error getting Bytes Received/sec value.\n";
goto cleanup;
return -1;
}
/*double */receivedRate = receivedCounterValue.doubleValue; // 这里的单位是字节/秒 (Bytes/second)
printf("Bytes Received/sec: %lf\n", receivedRate);
// 根据实际情况计算网络占用率,例如,这里简单的将发送和接收速率相加求平均
double networkUsage = (sentRate + receivedRate) / 2;
// 实际的网络占用率计算方法可能需要根据你的具体需求调整
printf("sent Kbps: %lf\n", sentRate*8/1000); // 转换成兆比特/秒 (Kbps)
printf("sent Mbps: %lf\n", sentRate * 8 / 1000000); // 转换成兆比特/秒 (Kbps)
printf("Received Kbps: %lf\n", receivedRate * 8 / 1000);// 转换成兆比特/秒 (Mbps)
printf("Received Mbps: %lf\n", receivedRate*8/1000000);// 转换成兆比特/秒 (Mbps)
}
// 关闭查询句柄
goto cleanup;
cleanup:
// 清理资源
if (queryHandle) PdhCloseQuery(queryHandle);
if (sentCounterHandle) PdhRemoveCounter(sentCounterHandle);
if (receivedCounterHandle) PdhRemoveCounter(receivedCounterHandle);
}
int main()
{
// 初始化
double sentVale = 0, receivedVale = 0;
getNetworkUsage(sentVale, receivedVale);
return 0;
}
输出
五、关于Kbps和KB/s以及Mbps和MB/s
对于上面转换分不清楚的同学,可以查看我早期的一篇博客
串口通信和以太网通信100Mbps速度的对比
更多推荐


所有评论(0)