135 lines
3.1 KiB
Go
135 lines
3.1 KiB
Go
package netstat
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// InterfaceStats 网卡统计信息
|
|
|
|
type InterfaceStats struct {
|
|
Name string //网卡名称
|
|
RxBytes uint64 //接收字节数
|
|
TxBytes uint64 //发送字节数
|
|
RxPackets uint64 //接收数据包数
|
|
TxPackets uint64 //发送数据包数
|
|
RxErrors uint64 //接收错误数
|
|
TxErrors uint64 //发送错误数
|
|
}
|
|
type TrafficRate struct {
|
|
Name string // 网卡名称
|
|
RxBytesRate float64 // 接收字节速率
|
|
TxBytesRate float64 // 发送字节速率
|
|
RxKbps float64 // 接收比特速率
|
|
TxKbps float64 // 发送比特速率
|
|
}
|
|
|
|
// GetInterfaceStats 获取所有网卡的统计信息
|
|
func GetInterfaceStats() ([]InterfaceStats, error) {
|
|
// 打开/proc/net/dev文件
|
|
file, err := os.Open("/proc/net/dev")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
// 创建scanner逐行读取文件内容
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
// 跳过前两行 头部信息
|
|
scanner.Scan()
|
|
scanner.Scan()
|
|
|
|
var stats []InterfaceStats
|
|
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
// 按空格分割
|
|
fields := strings.Fields(line)
|
|
if len(fields) < 17 {
|
|
continue
|
|
}
|
|
// 提取网卡名
|
|
ifaceName := strings.TrimSuffix(fields[0], ":")
|
|
if ifaceName == "lo" {
|
|
continue //跳过回环接口
|
|
}
|
|
|
|
stat := InterfaceStats{
|
|
Name: ifaceName,
|
|
RxBytes: parseUint64(fields[1]),
|
|
RxPackets: parseUint64(fields[2]),
|
|
RxErrors: parseUint64(fields[3]),
|
|
TxBytes: parseUint64(fields[9]),
|
|
TxPackets: parseUint64(fields[10]),
|
|
TxErrors: parseUint64(fields[11]),
|
|
}
|
|
stats = append(stats, stat)
|
|
}
|
|
return stats, scanner.Err()
|
|
}
|
|
|
|
func parseUint64(s string) uint64 {
|
|
var val uint64
|
|
fmt.Sscanf(s, "%d", &val)
|
|
return val
|
|
}
|
|
|
|
func CalculateRate(prev, curr []InterfaceStats, duration time.Duration) []TrafficRate {
|
|
prevMap := make(map[string]InterfaceStats)
|
|
for _, stat := range prev {
|
|
prevMap[stat.Name] = stat
|
|
}
|
|
var rates []TrafficRate
|
|
seconds := duration.Seconds()
|
|
for _, c := range curr {
|
|
p, exists := prevMap[c.Name]
|
|
if !exists {
|
|
continue
|
|
}
|
|
rxBytesDiff := c.RxBytes - p.RxBytes
|
|
txBytesDiff := c.TxBytes - p.TxBytes
|
|
rate := TrafficRate{
|
|
Name: c.Name,
|
|
RxBytesRate: float64(rxBytesDiff) / seconds,
|
|
TxBytesRate: float64(txBytesDiff) / seconds,
|
|
RxKbps: (float64(rxBytesDiff) * 8) / (seconds * 1024),
|
|
TxKbps: (float64(txBytesDiff) * 8) / (seconds * 1024),
|
|
}
|
|
rates = append(rates, rate)
|
|
}
|
|
return rates
|
|
}
|
|
|
|
func FormatBytes(bytes float64) string {
|
|
const unit = 1024
|
|
if bytes < unit {
|
|
return fmt.Sprintf("%.2f B", bytes)
|
|
}
|
|
div, exp := uint64(unit), 0
|
|
for n := bytes / unit; n >= unit; n /= unit {
|
|
div *= unit
|
|
exp++
|
|
}
|
|
return fmt.Sprintf("%.2f %cB", bytes/float64(div), "KMGTPE"[exp])
|
|
}
|
|
|
|
// FormatBps 格式化比特率为 1.23 Kbps、4.56 Mbps 等
|
|
func FormatBps(bps float64) string {
|
|
const unit = 1000
|
|
if bps < unit {
|
|
return fmt.Sprintf("%.2f bps", bps)
|
|
}
|
|
|
|
div, exp := float64(unit), 0
|
|
for n := bps / unit; n >= unit; n /= unit {
|
|
div *= unit
|
|
exp++
|
|
}
|
|
|
|
return fmt.Sprintf("%.2f %cps", bps/div, "KMGTPE"[exp])
|
|
}
|