直接读取/proc/net/dev可获取网卡实时流量,需跳过前两行表头,按空格分割提取非空token,取第1个(rx_bytes)和第9个(tx_bytes)字段,校验size≥9后转换为uint64_t,两次采样求差值除以时间间隔得速率。

直接读取 /proc/net/dev 文件就能拿到实时流量数据
Linux 内核通过 /proc/net/dev 暴露每张网卡的收发字节数、包数等统计信息,C++ 只需以文本方式打开并解析该文件即可——它不是设备节点,不需 ioctl 或 socket,也不依赖 libpcap。关键在于格式固定但首两行是表头,且字段对齐靠空格(非制表符),用 std::istringstream 直接按空格切分会因连续空格出错。
- 文件权限为 world-readable,普通用户可直接 open,无需 root
- 第 1 行是空行或注释(不同内核版本略有差异),第 2 行是字段名(
Inter-|Receive|...),真正数据从第 3 行开始 - 每行开头是网卡名(如
ens33:),注意末尾带冒号,解析时要 trim 掉 - 字段共 17 列,其中第 2 列(
rx_bytes)和第 10 列(tx_bytes)是核心流量值,单位为字节
用 std::ifstream + 手动跳过表头 + 字符串分割最稳妥
别用 operator>> 直接读整行再 split,因为字段含空格且列宽不一;也别依赖 std::getline 后调 std::stringstream + 多次 >>——它会跳过所有空白(包括中间缺失字段),导致列偏移。正确做法是:逐行读,跳过前两行,对每行先用 find_first_of(' ') 定位网卡名结束位置,再用 substr 提取后续数字部分,最后用 std::stringstream 按空格提取非空 token。
std::ifstream dev("/proc/net/dev");
std::string line;
// 跳过前两行
std::getline(dev, line); // 空行或注释
std::getline(dev, line); // 表头
while (std::getline(dev, line)) {
auto pos = line.find_first_of(" \t");
if (pos == std::string::npos) continue;
std::string iface = line.substr(0, pos);
if (iface.empty()) continue;
// 去掉末尾冒号
if (iface.back() == ':') iface.pop_back();
// 提取后续字段(跳过开头空白)
std::string fields = line.substr(pos + 1);
std::istringstream iss(fields);
std::vector<:string> tokens;
std::string tok;
while (iss >> tok) tokens.push_back(tok);
// tokens[0] 是 rx_bytes,tokens[8] 是 tx_bytes(索引从 0 开始)
if (tokens.size() >= 9) {
uint64_t rx = std::stoull(tokens[0]);
uint64_t tx = std::stoull(tokens[8]);
// 使用 rx/tx...
}
}</:string>
注意字段顺序在不同内核版本中是否一致
从 2.6 到 6.x,/proc/net/dev 的字段顺序基本稳定:第 1 字段是接收字节数(rx_bytes),第 9 字段是发送字节数(tx_bytes)——但这是按空格分割后的第 1 和第 9 个非空 token,不是原始行的第 1 和第 9 列。某些嵌入式发行版或定制内核可能裁剪字段(比如去掉压缩包统计),此时 tokens.size() 可能小于 9。建议加判断,避免 std::stoull 抛 std::out_of_range。
Linux AI 服务器 — 将 Linux 服务器转换为本地 AI 推理集群。使用 systemd、NVIDIA CUDA 实现无头 Linux AI,零 GUI 开销。
- 不要硬编码索引,先检查
tokens.size() >= 9再取tokens[0]和tokens[8] - 若需更高兼容性,可先解析第 2 行表头(如
rx_bytes出现在第几个位置),但实际中绝大多数场景直接按固定位置更轻量 - 字段名行(第 2 行)中,
rx_bytes总是在compressed左侧、rx_packets右侧,位置相对固定
两次读取做差值得到瞬时速率要小心时间窗口
仅读一次只能拿到累计值;要算 bps,必须间隔 Δt 秒读两次,再用 (new - old) / Δt。但 Δt 太小(如 100ms)会导致噪声大,Δt 太大(如 5s)则响应滞后。更关键的是:/proc/net/dev 是快照,两次读之间网卡可能 down/up、驱动重置计数器,导致差值为负或异常大。
- 每次读取后校验:若
new_rx ,说明计数器重置,应丢弃本次差值或打日志告警 - 建议最小采样间隔 ≥ 1 秒,生产环境常用 2–5 秒
- 不要用
std::chrono::steady_clock::now()计算 Δt 后直接除——浮点除法误差在低流量下放大明显,建议统一转成毫秒整数再算(bytes * 1000) / delta_ms
实际跑起来你会发现,最麻烦的不是读文件,而是处理网卡名里带空格(极少见)、字段缺失、以及某次读取恰好卡在内核更新计数器的瞬间。这些边界情况比语法本身更消耗调试时间。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










