构建实时网络速度监控面板:Python Flask + SSE 技术详解
本文将带你一步步构建一个实时网络速度监控面板,使用 Python Flask 后端和 Server-Sent Events (SSE) 前端技术。
项目概述
这个网络监控工具可以实时显示每个网络接口的下载和上传速度,类似于 Web 版本的 iftop
或 nload
命令。
功能特点
- 实时监控所有活跃网络接口
- 自动过滤回环接口和无效接口
- 按下载速度排序显示
- 同时显示字节每秒和比特每秒
- 简洁美观的 Web 界面
技术栈
- 后端: Python + Flask + psutil
- 前端: HTML + CSS + JavaScript (SSE)
- 通信: Server-Sent Events (SSE)
完整代码实现
后端代码 (app.py)
python
import time
import json
import psutil
from flask import Flask, Response, render_template_string
app = Flask(__name__)
def collect(interval: float = 1.0):
"""
收集网络接口统计信息
interval: 采样间隔时间(秒)
"""
# 获取第一次网络IO计数
prev = psutil.net_io_counters(pernic=True)
time.sleep(interval)
# 获取第二次网络IO计数
curr = psutil.net_io_counters(pernic=True)
stats = psutil.net_if_stats()
def is_active(name: str) -> bool:
"""检查网络接口是否活跃且不是回环接口"""
st = stats.get(name)
if not st or not st.isup:
return False
# 过滤回环接口
if name.lower() in ("lo", "loopback", "loopback pseudo-interface 1"):
return False
return True
summary = {"down_bps": 0.0, "up_bps": 0.0, "ifaces": []}
names = set(prev.keys()) & set(curr.keys())
for name in sorted(names):
if not is_active(name):
continue
# 计算速度(字节/秒)
p = prev[name]
c = curr[name]
down = max(c.bytes_recv - p.bytes_recv, 0) / interval
up = max(c.bytes_sent - p.bytes_sent, 0) / interval
summary["down_bps"] += down
summary["up_bps"] += up
summary["ifaces"].append({"name": name, "down_bps": down, "up_bps": up})
# 按下载速度降序排序
summary["ifaces"].sort(key=lambda x: x["down_bps"], reverse=True)
return summary
def format_rate(bytes_per_sec: float) -> str:
"""格式化速度显示"""
bits_per_sec = bytes_per_sec * 8
def human(n, unit):
for s in ["", "K", "M", "G", "T"]:
if n < 1024:
return f"{n:,.1f} {s}{unit}"
n /= 1024
return f"{n:,.1f} P{unit}"
return f"{human(bytes_per_sec, 'B/s')} ({human(bits_per_sec, 'bps')})"
@app.route("/metrics")
def metrics():
"""SSE 流端点,每秒推送一次网络数据"""
def stream():
while True:
data = collect(1.0)
yield f"data: {json.dumps(data)}\n\n"
return Response(stream(), mimetype="text/event-stream")
# HTML 模板
INDEX_HTML = """
<!doctype html>
<meta charset="utf-8" />
<title>Net Speed Panel</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 860px; margin: 24px auto; }
header { display: flex; align-items: baseline; justify-content: space-between; }
.total { font-size: 18px; margin: 12px 0; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 8px; border-bottom: 1px solid #eee; text-align: left; }
th { background: #fafafa; }
.down { color: #0b6; }
.up { color: #06b; }
.muted { color: #888; }
</style>
<header>
<h1>网络速度监控面板</h1>
<span class="muted">每秒刷新</span>
</header>
<div class="total" id="total">总计 加载中...</div>
<table>
<thead>
<tr><th>网卡</th><th>下行</th><th>上行</th></tr>
</thead>
<tbody id="tbody"></tbody>
</table>
<script>
function human(n, unit) {
const units = ['', 'K', 'M', 'G', 'T'];
let i = 0;
while (n >= 1024 && i < units.length - 1) { n /= 1024; i++; }
return `${n.toFixed(1)} ${units[i]}${unit}`;
}
function formatRate(bytesPerSec) {
const bps = bytesPerSec * 8;
return `${human(bytesPerSec, 'B/s')} (${human(bps, 'bps')})`;
}
const total = document.getElementById('total');
const tbody = document.getElementById('tbody');
const es = new EventSource('/metrics');
es.onmessage = (e) => {
const data = JSON.parse(e.data);
total.textContent = `总计 ↓ ${formatRate(data.down_bps)} ↑ ${formatRate(data.up_bps)}`;
tbody.innerHTML = '';
data.ifaces.forEach(({name, down_bps, up_bps}) => {
const tr = document.createElement('tr');
tr.innerHTML = `<td>${name}</td><td class="down">↓ ${formatRate(down_bps)}</td><td class="up">↑ ${formatRate(up_bps)}</td>`;
tbody.appendChild(tr);
});
};
</script>
"""
@app.route("/")
def index():
return render_template_string(INDEX_HTML)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=False)
核心原理详解
1. 网络速度计算原理
python
def collect(interval: float = 1.0):
prev = psutil.net_io_counters(pernic=True) # 第一次采样
time.sleep(interval) # 等待指定间隔
curr = psutil.net_io_counters(pernic=True) # 第二次采样
# 计算速度 = (第二次计数 - 第一次计数) / 时间间隔
down = (c.bytes_recv - p.bytes_recv) / interval
up = (c.bytes_sent - p.bytes_sent) / interval
这种方法通过两次采样之间的差值来计算瞬时速度,比直接读取瞬时值更准确。
2. Server-Sent Events (SSE) 技术
SSE 允许服务器主动向客户端推送数据,非常适合实时监控场景:
python
@app.route("/metrics")
def metrics():
def stream():
while True:
data = collect(1.0) # 每秒收集一次数据
yield f"data: {json.dumps(data)}\n\n" # SSE 格式
return Response(stream(), mimetype="text/event-stream")
前端通过 EventSource API 接收数据:
javascript
const es = new EventSource('/metrics');
es.onmessage = (e) => {
const data = JSON.parse(e.data);
// 更新界面
};
3. 速度单位换算
python
def format_rate(bytes_per_sec: float) -> str:
bits_per_sec = bytes_per_sec * 8 # 转换为比特
def human(n, unit):
# 自动选择合适的单位 (B, KB, MB, GB, TB)
for s in ["", "K", "M", "G", "T"]:
if n < 1024:
return f"{n:,.1f} {s}{unit}"
n /= 1024
return f"{n:,.1f} P{unit}"
return f"{human(bytes_per_sec, 'B/s')} ({human(bits_per_sec, 'bps')})"
部署和运行
安装依赖
bash
pip install flask psutil
运行应用
bash
python app.py
访问 http://localhost:5000 即可看到监控面板。
总结
通过这个项目,我们学习了:
- 使用
psutil
库获取系统网络信息 - SSE 技术的原理和实现方式
- 实时数据计算的差分方法
- 前后端分离的 Web 应用架构
这个网络监控工具不仅实用,也是学习实时 Web 应用开发的优秀示例。你可以基于这个基础继续添加更多功能,打造属于自己的系统监控工具。
希望这个教程对你有所帮助!