2012年7月24日 星期二

在 Linux 上偵測系統頻寬

原本有找到 nmon 這個工具可以在 Linux 上偵測頻寬
在 Linux 監控系統資源:nmon for Linux
不過它好像只有直接執行 nmon 觀察,才會有 peak 的數據出現
如果要輸出成檔案時,nmon 只會輸出當下的流量數據,這樣就無法達成原本的需求了。
在看 nmon 輸出的資料時,發現在網路的部份它似乎也只是去分析 /proc/net/dev 提供的資訊
例如現在去看 /proc/net/dev,顯示累計傳輸了 N Bytes
一秒之後再看一次 /proc/net/dev,會顯示累計傳輸 N+M Bytes
因此可以算出這 1 秒的流量是 M Byte/s。
既然 nmon 實際上也只是輸出 /proc/net/dev 的數據,那其實直接自己去查詢 /proc/net/dev 就好了!

參考資料:
1、Linux 下觀查網路流量
2、查詢網卡流量

這邊我參考的 shell script 是 [2] 的 script。

#!/bin/bash
# test network width
function usage {
  echo "Usage: $0  "
  echo "    e.g. $0 eth0 2"
  exit 65
}

if [ $# -lt 2 ];then
  usage
fi

typeset in in_old dif_in
typeset out out_old dif_out
typeset timer
typeset eth
eth=$1
timer=$2
in_old=$(cat /proc/net/dev | grep $eth | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk ' { print $1 }' )
out_old=$(cat /proc/net/dev | grep $eth | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk ' { print $9 }' )
sleep ${timer}
in=$(cat /proc/net/dev | grep $eth | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk ' { print $1 }' )
out=$(cat /proc/net/dev | grep $eth | sed -e "s/\(.*\)\:\(.*\)/\2/g" | awk ' { print $9 }' )
dif_in=$(((in-in_old)/timer))
dif_out=$(((out-out_old)/timer))
# bytes per seconds
echo "IN:${dif_in} OUT:${dif_out}"
exit 0

因為我的需求是我只要當下的流量,我不需要讓它一直重複執行
所以我把無窮迴圈的部份拿掉了,並且輸出的格式改成比較容易分析的格式
例如假設 script 存成 /usr/local/bandwidth.sh
則呼叫時可以輸入像是
bash /usr/local/bandwidth.sh eth0 1
這樣表示要輸出 eth0 這張網卡一秒內的流量
而輸出就會長這樣子:
IN:646 OUT:148
表示下載的流量是 646 Byte/s、上傳流量是 148 Byte/s。

在 Java 的部份,可以把讀取流量的部分獨立寫成一個 class
例如:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;

import org.apache.commons.io.IOUtils;

public class myMonitor implements Runnable {
  @Override
  public void run() {
    String cmd = "/usr/local/bandwidth.sh";
    int flow = this.getCurrentFlowOfMac(cmd, "eth0");
  }

  // Get the current bandwidth.
  private int getCurrentFlowOfMac (String command, String eth) {
    Process process = null;
    InputStreamReader isr = null;
    BufferedReader br = null;
    String line = null;
    try {
      String cmd = "bash " + command + " " + eth + " 1";
      process = Runtime.getRuntime().exec(cmd);
      isr = new InputStreamReader(process.getInputStream());
      br = new BufferedReader(isr);
      if( (line = br.readLine()) != null ) {
        // Read the returned string and get the output part.
        return Integer.parseInt(line.split(" ")[1].split(":")[1]);
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if(br != null) br.close();
        if(isr != null) isr.close();
        if(process != null){
          IOUtils.closeQuietly(process.getInputStream());
          IOUtils.closeQuietly(process.getOutputStream());
          IOUtils.closeQuietly(process.getErrorStream());
        }
      } catch (Exception e) {}
    }
    return 0;
  }
}
上述的程式碼中,因為我會用定時執行的方式去跑這段程式
一直抓現在的流量,才有辦法確認比較真實的流量上限
所以這支是實作 Runnable,每被執行一次就觀察接下來的一秒的流量變化。

沒有留言: