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

Linux C 語言實戰:讀取 /proc/net/dev 獲取網卡流量統計 (ifconfig 核心邏輯)

     編輯:關於C

前言:Linux 下網卡流量從哪來?

在 Linux 系統中,網卡統計資訊 (接收/發送位元組、封包數、錯誤、丟包等) 由核心維護,透過虛擬檔案系統 **/proc/net/dev** 公開給使用者空間。ifconfig、ip -s link、netstat -i 等工具本質上都是解析此檔案。

/proc/net/dev 格式解析

$ cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo: 123456   1234    0    0    0     0          0         0  123456   1234    0    0    0     0       0          0
  eth0: 987654321 123456   0    0    0     0          0         0  123456789 123456   0    0    0     0       0          0
  wlan0: 0        0    0    0    0     0          0         0        0        0    0    0    0     0       0          0

每行欄位 (以 eth0 為例):

索引欄位名說明
1Interface介面名稱 (含尾隨 :)
2rx_bytes接收位元組數 ← 重點
3rx_packets接收封包數
4rx_errs接收錯誤
5rx_drop接收丟包
6rx_fifoFIFO 錯誤
7rx_frame幀錯誤
8rx_compressed壓縮封包
9rx_multicast多播封包
10tx_bytes發送位元組數 ← 重點
11tx_packets發送封包數
12tx_errs發送錯誤
13tx_drop發送丟包
14tx_fifoFIFO 錯誤
15tx_colls碰撞
16tx_carrier載波錯誤
17tx_compressed壓縮封包

C 語言解析實作

#include 
#include 
#include 
#include 
#include 
#include 

typedef struct {
    unsigned long long rx_bytes;
    unsigned long long tx_bytes;
    const char *iface;
} NetStats;

// 回傳 0 成功,-1 失敗
int get_net_stats(const char *iface, NetStats *out) {
    if (!iface || !out) return -1;
    if (strlen(iface) > 100) return -1;  // 防禦

    int fd = open("/proc/net/dev", O_RDONLY);
    if (fd < 0) {
        perror("open /proc/net/dev");
        return -1;
    }

    char buf[4096];
    ssize_t n = read(fd, buf, sizeof(buf) - 1);
    close(fd);
    if (n <= 0) {
        if (n < 0) perror("read");
        return -1;
    }
    buf[n] = '\0';

    // 尋找介面名 (格式: "eth0:")
    char target[128];
    snprintf(target, sizeof(target), "%s:", iface);
    char *line = strstr(buf, target);
    if (!line) {
        fprintf(stderr, "介面 %s 不存在\n", iface);
        return -1;
    }

    // 解析該行數值 (跳過介面名)
    line = strchr(line, ':');
    if (!line) return -1;
    line++;  // 跳過 ':'

    // 使用 sscanf 直接提取 rx_bytes (第1欄) 和 tx_bytes (第9欄)
    unsigned long long rx, tx;
    // 格式: %*s 跳過 rx_packets, rx_errs... 共 7 個欄位
    if (sscanf(line, "%llu %*u %*u %*u %*u %*u %*u %*u %llu", &rx, &tx) != 2) {
        fprintf(stderr, "解析失敗\n");
        return -1;
    }

    out->rx_bytes = rx;
    out->tx_bytes = tx;
    out->iface = iface;
    return 0;
}

// 人性化顯示 (自動單位)
void print_human(unsigned long long bytes, const char *label) {
    const char *units[] = {"B", "KB", "MB", "GB", "TB"};
    int i = 0;
    double val = bytes;
    while (val >= 1024 && i < 4) {
        val /= 1024;
        i++;
    }
    printf("%s: %.2f %s\n", label, val, units[i]);
}

int main(int argc, char *argv[]) {
    const char *iface = (argc > 1) ? argv[1] : "eth0";
    NetStats stats;

    if (get_net_stats(iface, &stats) == 0) {
        printf("介面: %s\n", iface);
        print_human(stats.rx_bytes, "接收流量");
        print_human(stats.tx_bytes, "發送流量");
    } else {
        fprintf(stderr, "獲取失敗\n");
        return 1;
    }
    return 0;
}

編譯與執行

$ gcc -o netstat_netdev netstat_netdev.c
$ ./netstat_netdev eth0
介面: eth0
接收流量: 941.82 MB
發送流量: 117.76 MB

$ ./netstat_netdev lo
介面: lo
接收流量: 120.63 KB
發送流量: 120.63 KB

進階:即時流量監控 (每秒差分)

#include 

int main() {
    const char *iface = "eth0";
    NetStats prev, curr;
    get_net_stats(iface, &prev);

    while (1) {
        sleep(1);
        if (get_net_stats(iface, &curr) != 0) break;

        unsigned long long rx_rate = curr.rx_bytes - prev.rx_bytes;
        unsigned long long tx_rate = curr.tx_bytes - prev.tx_bytes;

        printf("\r%s: ↓ %6.2f KB/s  ↑ %6.2f KB/s", iface,
               rx_rate / 1024.0, tx_rate / 1024.0);
        fflush(stdout);

        prev = curr;
    }
    return 0;
}

替代方案對比

方法優點缺點適用場景
讀取 /proc/net/dev無需權限、極輕量、標準 Linux需自行解析、32位系統計數器可能溢位嵌入式、簡單監控、無 lib 依賴
libnl (netlink)官方 API、支援完整屬性、非同步通知需連結庫、學習曲線陡NetworkManager、複雜網管工具
getifaddrs + ioctl (SIOCETHTOOL)POSIX 可攜、可取介面旗標/MTU不直接給計數器、需 ioctl跨平台 (BSD/macOS 也支援)
system("ifconfig") / popen快速原型效能差、格式依賴、安全風險臨時腳本、不推薦生產

注意事項

  1. 計數器溢位:32 位系統 unsigned long 4GB 即溢位,建議用 unsigned long long (64 位) 讀取,核心 2.6+ 已支援 64 位計數器。
  2. 虛擬介面:docker0, veth*, br-* 等也會出現,按名稱過濾。
  3. 權限:/proc/net/dev 全域可讀,無需 root。
  4. 即時性:核心即時更新,讀取即為當下快照。

總結

直接解析 /proc/net/dev 是 Linux 下獲取網卡流量最輕量、無依賴、標準的方法。掌握其欄位定義與 sscanf 解析技巧,即可輕鬆實作流量監控、頻寬統計、異常流量告警等功能,無需依賴重型庫或外部命令。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved