收起左侧

网卡流量监控

1
回复
173
查看
[ 复制链接 ]

3

主题

48

回帖

0

牛值

初出茅庐

图片.png

看到论坛里大家都需要一个网卡流量监测的软件,就用ai写了一个,本人亲测用效:

访问 http://飞牛NAS_IP:8080

要修改端口的话找到python文件中这一行:

app.run(host='0.0.0.0', port=8080, debug=False)

一、前置准备:安装依赖

1. ssh连接到飞牛,sudo -i 提升权限

2. 安装核心依赖包(仅适用于飞牛nas)

# 更新源(确保能找到包)
apt update

# 安装flask和psutil的系统包
apt install -y python3-flask python3-psutil

二、创建目录(统一存放文件)

mkdir -p ~/network_monitor/templates
cd ~/network_monitor

三、编写前端页面(实时展示+曲线图)

cat > ~/network_monitor/templates/index.html << 'EOF'
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>网络流量监控(24小时/10秒刷新)</title>
    <script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }
        .container { max-width: 1200px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
        .stats { margin: 20px 0; padding: 15px; background: #e8f4f8; border-radius: 6px; }
        .stat-item { margin: 10px 0; font-size: 16px; }
        #chart { width: 100%; height: 500px; margin-top: 20px; }
        select { padding: 8px; font-size: 16px; margin-bottom: 10px; }
        .title { color: #333; margin-bottom: 20px; }
        .refresh-tip { color: #666; font-size: 14px; margin-bottom: 10px; }
    </style>
</head>
<body>
    <div class="container">
        <h1 class="title">网络流量监控</h1>
        <div class="refresh-tip">实时数据:每秒刷新 | 曲线图:每10秒刷新(最近24小时,每10秒一个数据点)</div>
  
        <label for="interface">选择监控网卡:</label>
        <select id="interface">
            {% for iface in interfaces %}
                <option value="{{ iface }}">{{ iface }}</option>
            {% endfor %}
        </select>

        <!-- 实时数据区(每秒刷新) -->
        <div class="stats">
            <div class="stat-item">当前网卡:<span id="current-interface">--</span></div>
            <div class="stat-item">总发送流量:<span id="total-sent">0.00</span> MB</div>
            <div class="stat-item">总接收流量:<span id="total-recv">0.00</span> MB</div>
            <div class="stat-item">实时发送速率:<span id="sent-rate">0.00</span> KB/s</div>
            <div class="stat-item">实时接收速率:<span id="recv-rate">0.00</span> KB/s</div>
        </div>

        <!-- 曲线图(每10秒强制刷新,光滑曲线) -->
        <div id="chart"></div>
    </div>

    <script>
        // 初始化图表
        var chart = echarts.init(document.getElementById('chart'));
        var currentInterface = "";
  
        // 刷新间隔(从后端传过来)
        var realTimeRefresh = {{ real_time_refresh }};  // 1000ms = 1秒
        var chartRefresh = {{ chart_refresh }};        // 10000ms = 10秒

        // 完整的图表配置(核心:补全所有配置,避免初始化为空)
        function getChartOption(timestamp, sent, recv) {
            return {
                title: { text: '最近24小时网络流量速率趋势 (KB/s)' },
                tooltip: { 
                    trigger: 'axis',
                    formatter: function(params) {
                        return params[0].name + '<br/>' +
                               params[0].seriesName + ': ' + params[0].data + ' KB/s<br/>' +
                               params[1].seriesName + ': ' + params[1].data + ' KB/s';
                    }
                },
                legend: { data: ['发送速率', '接收速率'] },
                grid: { left: '3%', right: '4%', bottom: '15%', containLabel: true },
                xAxis: { 
                    type: 'category', 
                    data: timestamp,
                    axisLabel: {
                        interval: Math.ceil(timestamp.length / 20),  // 自动调整标签密度
                        rotate: 45    // 旋转避免重叠
                    }
                },
                yAxis: { type: 'value', name: 'KB/s' },
                series: [
                    { 
                        name: '发送速率', 
                        type: 'line', 
                        data: sent, 
                        smooth: true,  // 光滑曲线
                        lineStyle: { width: 2 },  // 线条加粗
                        itemStyle: { color: '#4285F4' }
                    },
                    { 
                        name: '接收速率', 
                        type: 'line', 
                        data: recv, 
                        smooth: true,
                        lineStyle: { width: 2 },
                        itemStyle: { color: '#0F9D58' }
                    }
                ]
            };
        }

        // 更新实时数据(每秒)
        function updateRealTimeStats() {
            fetch(`/api/stats/${currentInterface}`)
                .then(response => response.json())
                .then(data => {
                    if (data.error) {
                        **(data.error);
                        return;
                    }
                    document.getElementById('total-sent').textContent = data.total_sent;
                    document.getElementById('total-recv').textContent = data.total_recv;
                    document.getElementById('sent-rate').textContent = data.sent_rate;
                    document.getElementById('recv-rate').textContent = data.recv_rate;
                })
                .catch(error => console.error('实时数据更新失败:', error));
        }

        // 强制更新曲线(每10秒必执行,补全配置)
        function updateChart() {
            fetch('/api/history')
                .then(res => res.json())
                .then(history => {
                    // 用完整配置刷新图表
                    chart.setOption(getChartOption(history.timestamp, history.sent, history.recv), true);
                })
                .catch(error => console.error('图表更新失败:', error));
        }

        // 页面初始化
        function initPage() {
            currentInterface = document.getElementById('interface').value;
            document.getElementById('current-interface').textContent = currentInterface;
            updateRealTimeStats();
            updateChart();
        }

        // 页面加载完成后启动
        window.onload = function() {
            initPage();
            // 实时数据每秒刷新
            setInterval(updateRealTimeStats, realTimeRefresh);
            // 曲线每10秒强制刷新
            setInterval(updateChart, chartRefresh);
        };

        // 网卡切换事件
        document.getElementById('interface').addEventListener('change', function() {
            currentInterface = this.value;
            document.getElementById('current-interface').textContent = currentInterface;
            updateRealTimeStats();
            updateChart();
        });

        // 窗口自适应
        window.addEventListener('resize', function() {
            chart.resize();
        });
    </script>
</body>
</html>
EOF

四、编写后端逻辑(数据采集+API接口)

cat > ~/network_monitor/network_monitor.py << 'EOF'
from flask import Flask, render_template, jsonify
import psutil
import time
from datetime import datetime, timedelta

app = Flask(__name__)

# 核心配置
MAX_HISTORY_SECONDS = 24 * 3600  # 保留最近24小时数据
SAMPLE_INTERVAL = 10              # 每10秒采集一个数据点(保证曲线10秒有新数据)
REAL_TIME_REFRESH = 1             # 实时数据每秒刷新
CHART_REFRESH = 10                # 曲线每10秒刷新

# 历史数据存储(10秒一个点,最多24小时)
history_data = {
    "timestamp": [],  # 格式:HH:MM:SS
    "sent": [],       # 发送速率 (KB/s)
    "recv": []        # 接收速率 (KB/s)
}

# 临时累计数据(用于计算10秒平均速率)
temp_data = {
    "start_time": None,
    "sent_bytes": 0,
    "recv_bytes": 0
}

# 全局变量(实时速率计算)
last_io = None
last_time = None

# 获取网卡列表(排除回环地址)
def get_network_interfaces():
    interfaces = []
    for name, addrs in psutil.net_if_addrs().items():
        if name != "lo":
            interfaces.append(name)
    return interfaces if interfaces else ["eth0"]

# 初始化临时数据
def init_temp_data():
    temp_data["start_time"] = time.time()
    temp_data["sent_bytes"] = 0
    temp_data["recv_bytes"] = 0

# 获取实时流量 + 每10秒采样
def get_network_stats(interface):
    global last_io, last_time
    try:
        # 获取网卡IO数据
        net_io = psutil.net_io_counters(pernic=True).get(interface, None)
        if not net_io:
            return {"error": f"网卡 {interface} 不存在"}
  
        current_time = time.time()
        now = datetime.now()
  
        # 首次调用初始化
        if last_io is None or last_time is None:
            last_io = net_io
            last_time = current_time
            init_temp_data()
            return {
                "interface": interface,
                "total_sent": round(net_io.bytes_sent / 1024 / 1024, 2),
                "total_recv": round(net_io.bytes_recv / 1024 / 1024, 2),
                "sent_rate": 0.0,
                "recv_rate": 0.0
            }
  
        # 计算实时速率(每秒更新)
        time_diff = current_time - last_time
        if time_diff < 0.1:
            realtime_sent = 0.0
            realtime_recv = 0.0
        else:
            realtime_sent = (net_io.bytes_sent - last_io.bytes_sent) / 1024 / time_diff
            realtime_recv = (net_io.bytes_recv - last_io.bytes_recv) / 1024 / time_diff
  
        # 累计10秒内的字节数
        temp_data["sent_bytes"] += (net_io.bytes_sent - last_io.bytes_sent)
        temp_data["recv_bytes"] += (net_io.bytes_recv - last_io.bytes_recv)
  
        # 更新全局变量
        last_io = net_io
        last_time = current_time
  
        # 每10秒生成一个数据点(核心)
        if current_time - temp_data["start_time"] >= SAMPLE_INTERVAL:
            # 计算10秒平均速率
            avg_sent = temp_data["sent_bytes"] / 1024 / SAMPLE_INTERVAL
            avg_recv = temp_data["recv_bytes"] / 1024 / SAMPLE_INTERVAL
      
            # 添加到历史数据
            history_data["timestamp"].append(now.strftime("%H:%M:%S"))
            history_data["sent"].append(round(avg_sent, 2))
            history_data["recv"].append(round(avg_recv, 2))
      
            # 清理超过24小时的旧数据
            max_points = int(MAX_HISTORY_SECONDS / SAMPLE_INTERVAL)
            if len(history_data["timestamp"]) > max_points:
                history_data["timestamp"].pop(0)
                history_data["sent"].pop(0)
                history_data["recv"].pop(0)
      
            # 重置临时数据
            init_temp_data()
  
        # 返回实时数据
        return {
            "interface": interface,
            "total_sent": round(net_io.bytes_sent / 1024 / 1024, 2),
            "total_recv": round(net_io.bytes_recv / 1024 / 1024, 2),
            "sent_rate": round(realtime_sent, 2),
            "recv_rate": round(realtime_recv, 2)
        }
    except Exception as e:
        return {"error": str(e)}

# 首页路由
@app.route('/')
def index():
    interfaces = get_network_interfaces()
    return render_template(
        'index.html',
        interfaces=interfaces,
        real_time_refresh=REAL_TIME_REFRESH*1000,
        chart_refresh=CHART_REFRESH*1000
    )

# 实时数据API
@app.route('/api/stats/<interface>')
def api_stats(interface):
    stats = get_network_stats(interface)
    return jsonify(stats)

# 历史数据API(曲线用)
@app.route('/api/history')
def api_history():
    return jsonify(history_data)

if __name__ == '__main__':
    init_temp_data()
    app.run(host='0.0.0.0', port=8080, debug=False)
EOF

五、手动运行/停止

1. 启动程序(后台静默运行)

cd ~/network_monitor
nohup python3 network_monitor.py > /dev/null 2>&1 &

访问地址:http://服务器IP:8080

2. 停止程序

pkill -f network_monitor.py

飞牛 NAS 开机自启

全程在 root@fnOS:~# 下执行:

第一步:用screen实现开机自启(飞牛NAS专用,永不卡)

1. 安装screen(飞牛可能没有,先装)

apt install -y screen

2. 一键创建开机自启脚本(核心)

cat > /etc/rc.local << 'EOF'
#!/bin/bash
# 等待网络启动完成
sleep 10
# 用screen后台启动监控程序(路径是你的/root/network_monitor)
screen -dmS network-monitor python3 /root/network_monitor/network_monitor.py
exit 0
EOF

3. 给脚本加执行权限

chmod +x /etc/rc.local

4. 立即启动程序(不用等重启)

screen -dmS network-monitor python3 /root/network_monitor/network_monitor.py

第三步:验证是否成功

# 看screen会话是否存在(有就是成功)
screen -ls
# 输出类似:1234.network-monitor (Detached)

访问 http://飞牛NAS_IP:8080,能看到监控页面就彻底搞定!

后续维护命令(超简单)

功能 命令
查看程序日志 screen -r network-monitor(退出按Ctrl+A+D)
停止程序 screen -S network-monitor -X quit
重启程序 screen -S network-monitor -X quit && screen -dmS network-monitor python3 /root/network_monitor/network_monitor.py

验证开机自启(可选)

# 重启NAS
reboot
# 重启后执行
screen -ls

能看到 network-monitor会话,访问页面正常,就说明开机自启生效了。

收藏
送赞 1
分享

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

0

主题

3

回帖

0

牛值

江湖小虾

部署后无流量使用豆包分析将编写前端 **(data.error); 替换为 console.log(data.error);,改后重启显示正常了。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则