Linuxでネットワークインタフェースの活動状況を調べる by Rust


以前、Linuxでネットワークインタフェースの活動状況を調べる by Golang という記事を書いたのですが、最近Rustを勉強し始めたので、同様のものをRustで書いてみました。

やっていること

/sys/class/net/<network_if>/statistics/ から受信、送信の累計のバイト数がわかるので、周期的にそれを表示しています。

ソースをここに貼ります。

main.rs
use std::env;
use std::fs;
extern crate chrono;
extern crate schedule_recv;
use schedule_recv::periodic_ms;

fn read_transfer_bytes(f: &str) -> u64 {
    match fs::read_to_string(f) {
        Ok(s) => s.trim().parse().unwrap_or(0),
        Err(err) => {
            panic!("Failed to read:{} Err={:?}", f, err);
        }
    }
}

fn net_activity(ifname: &str) {
    let interval = 2000;
    let txf = &format!("/sys/class/net/{}/statistics/tx_bytes", ifname);
    let rxf = &format!("/sys/class/net/{}/statistics/rx_bytes", ifname);
    let tick = periodic_ms(interval);
    let mut tx_prev = read_transfer_bytes(txf);
    let mut rx_prev = read_transfer_bytes(rxf);
    let td = interval as f64 * 1e-3;
    loop {
        tick.recv().unwrap();
        let tx = read_transfer_bytes(txf);
        let rx = read_transfer_bytes(rxf);
        println!(
            "t={}, tx={}, rx={}, tx/s={:.1} KB/s, rx/s={:.1} KB/s",
            chrono::Utc::now().timestamp(),
            tx,
            rx,
            ((tx - tx_prev) as f64) / td / 1024f64,
            ((rx - rx_prev) as f64) / td / 1024f64
        );
        tx_prev = tx;
        rx_prev = rx;
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        eprintln!("Usage: {} ifname", args[0]);
        eprintln!("  For example, {} eth0", args[0]);
        eprintln!("  You can find ifname by `ls /sys/class/net`");
        return;
    }
    net_activity(&args[1]);
}

Cargo.toml に追加したのは以下の通り。

[dependencies]
schedule_recv = "0.1"
chrono = "0.4"

実行例

$ ls /sys/class/net/
enp0s31f6  enx00051bd1473c  lo  wlp4s0

$ cargo run enp0s31f6
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s                   
     Running `target/debug/net_activity enp0s31f6`
t=1537868984, tx=405623729, rx=98837205807, tx/s=0.0 KB/s, rx/s=0.1 KB/s
t=1537868986, tx=405623729, rx=98837206182, tx/s=0.0 KB/s, rx/s=0.2 KB/s
t=1537868988, tx=405623930, rx=98837208653, tx/s=0.1 KB/s, rx/s=1.2 KB/s
t=1537868990, tx=405624302, rx=98837209502, tx/s=0.2 KB/s, rx/s=0.4 KB/s
^C

メモ

ファイルを一括で読んでStringにするのに、std::fs::read_to_string() というちょうどいいものがあったので、それを使った。

周期的に実行するには、schedule_recvというクレートを使用した。Sleepで待つと少しずつ遅れてしまうので。

タイムスタンプには、chronoというクレートを使用した。std::time::SystemTime より機能が豊富。