以前、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 より機能が豊富。