vnStat 是一款开源的网络流量统计工具,可以方便的查看当天,当月流量统计。官网地址:

https://humdi.net/vnstat/

安装

在 Debian/Ubuntu 下非常简单

sudo apt install vnstat vnstati

假设网卡名为 eth0,该配置在 /etc/vnstat.conf 中,安装结束后初始化数据库

sudo vnstat -u -i eth0

添加为开机启动

sudo update-rc.d vnstat enable

使用

直接输入 vnstat

vnstat -l  # 或者 `--live` 实时流量
vnstat -h  # 按小时查询流量
vnstat -d  # 按日显示流量信息
vnstat -w  # 按周显示流量信息
vnstat -m  # 按月显示流量信息
vnstat -t  # 显示流量最高top10天

图形化输出可以使用 vnstati ,将月流量统计图输出到图片

vnstati -i eth0 - -months - -output /dir/month.png

获取每月用量

#!/bin/bash
# 绑定网卡,一般默认eth0, 根据实际情况填写
interface="eth0"

# 定义阈值,单位GiB
traffic_limit="14"

# 获取每月用量 $11:进站+出站;$10是:出站;$9是:进站
traffic="$(vnstat --oneline -i "${interface}" | awk -F ';' '{print $11}')"

if [[ "${traffic}" =~ ^.+GiB$ ]] && [[ "${traffic%.*}" -ge ${traffic_limit} ]]; then
     echo "当前流量超过限制:${traffic}"
# 执行后续操作
#    sudo halt
else
     echo "当前流量未超过限制:${traffic}"
fi

脚本

#!/bin/bash
# 定义阈值(以GB为单位) 执行 vnstat --json 命令并将输出保存到变量中
THRESHOLD_GIB=1700

vnstat_output=$(vnstat --json)
# 提取当前年份和月份
current_year=$(echo "$vnstat_output" | jq -r '.interfaces[0].traffic.month[0].date.year')
current_month=$(echo "$vnstat_output" | jq -r '.interfaces[0].traffic.month[0].date.month')


# 在"month"部分找到相应的"rx"和"tx"值
rx_value_bytes=$(echo "$vnstat_output" | jq -r '.interfaces[0].traffic.month[0].rx') 
rx_value_gb=$(echo "scale=2; $rx_value_bytes / 1024 / 1024 / 1024" | bc) 
tx_value_bytes=$(echo "$vnstat_output" | jq -r '.interfaces[0].traffic.month[0].tx') 
tx_value_gb=$(echo "scale=2; $tx_value_bytes / 1024 / 1024 / 1024" | bc) 

# 计算总流量
total_traffic=$(echo "$rx_value_gb + $tx_value_gb" | bc)


echo "当前月份接收流量 : $rx_value_gb GB" 
echo "当前月份发送流量 : $tx_value_gb GB"
echo "当前月份流量总计 : $total_traffic GB"

# 检查是否大于阈值
if (( $(echo "$total_traffic > $THRESHOLD_GIB" | bc -l) )); then 
    echo "流量超过阈值,正在执行关机操作..."
#   如果要执行重启就把下面的#去掉	
#     sudo halt
else 
    echo "本月流量充足" 
fi

发送 Telegram 通知

## 流量超过阈值就发送消息提醒

### config.json
# {
#   "telegram_bot_token": "xxxxx:xxxxxxx",
#   "chat_id": "xxxx",
#   "monthly_limit_gb": 100
# }

import json
import requests
import schedule
import time
import psutil
from datetime import datetime

def load_config():
    with open("config.json", "r") as file:
        return json.load(file)

def log_initial_traffic_usage():
    today = datetime.now()
    if today.day == 1:  # Check if it is the first day of the month
        net_io = psutil.net_io_counters(pernic=True).get('ens5')
        if net_io:
            total_bytes_initial = net_io.bytes_sent + net_io.bytes_recv
            print(f'{total_bytes_initial}')
            with open("traffic_usage.txt", "w") as file:
                file.write(f"{total_bytes_initial}\n")

def get_current_month_usage():
    try:
        with open("traffic_usage.txt", "r") as file:
            initial_bytes = int(file.readline().strip())
            net_io = psutil.net_io_counters(pernic=True).get('ens5')
            if net_io:
                current_total_bytes = net_io.bytes_sent + net_io.bytes_recv
                used_bytes = current_total_bytes - initial_bytes
                used_gb = used_bytes / (1024**3)  # Convert to GB
                return used_gb
    except FileNotFoundError:
        print("Initial traffic usage file not found. Make sure it's generated at the beginning of the month.")
        return None

def send_telegram_message(message, config):
    url = f"https://api.telegram.org/bot{config['telegram_bot_token']}/sendMessage"
    data = {
        "chat_id": config["chat_id"],
        "text": message
    }
    requests.post(url, data=data)

def check_traffic_and_notify(config):
    used_gb = get_current_month_usage()
    print(f'Already used: {used_gb} GB')
    if used_gb is not None and used_gb > config["monthly_limit_gb"]:
        send_telegram_message(f"Attention: Monthly traffic limit exceeded. Used: {used_gb:.2f} GB", config)

config = load_config()

schedule.every().day.at("00:01").do(log_initial_traffic_usage)
schedule.every(15).seconds.do(check_traffic_and_notify, config)

while True:
    schedule.run_pending()
    time.sleep(1)

总结

有了 vnstat 就可以自己写脚本来定时完成流量监控,比如在 AWS 上,如果发现流量超出了阈值,可以写 Telegram Bot 通知,也可以直接禁用相关的端口。