侧边栏壁纸
博主头像
鱼箴日记,AI,Java,Liunx,Spring,Spring AI博主等级

行动起来,活在当下

  • 累计撰写 20 篇文章
  • 累计创建 12 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

tcp-monitor:用 Python 和 HTML,给 Linux TCP 连接数画一条趋势线

Administrator
2026-11-09 / 0 评论 / 0 点赞 / 2 阅读 / 6720 字 / 正在检测是否收录...

排查服务器问题时,我们经常会执行一条命令,看看当前有多少 TCP 连接:

ss -Htn state established | wc -l

如果只关心某个服务端口,还可以加上筛选条件:

ss -Htn state established '( sport = :40002 )' | wc -l

这能回答“现在有多少连接”,但当问题发生在几个小时前,单次查询就不够用了。

例如,机器人服务偶尔出现集中掉线,等我们登录服务器时,连接可能已经恢复。此时更想知道的是:连接数从什么时候开始下降?持续了多久?哪个端口受到影响?恢复后是否回到了原来的水平?

围绕这些需求,我做了一个小工具:tcp-monitor。

它每分钟采集一次 TCP 连接数,将结果保存到文本文件,再通过 HTML 页面展示趋势。支持多个端口分别查看、自定义时间范围,以及按天滚动清理历史数据。

整个工具不需要数据库,也不需要安装第三方 Python 包。

项目的组成很直接:

tcp-monitor/
├── tcp-monitor.sh        # 启动、停止、重启与状态查询
├── tcp_monitor.py        # 采集、数据保留及 HTTP 服务
├── index.html            # 趋势展示页面
├── test_tcp_monitor.py   # 采集与历史数据测试
└── test_launcher.sh      # 启动脚本测试

采集程序使用 Linux 的 ss 获取连接快照,网页使用原生 Canvas 绘制曲线,无需从外部 CDN 加载图表库。具体实现可以查看仓库中的 Python 脚本和 HTML 页面。

部署时,服务器需要具备 Python 3.8 及以上版本、Bash、`ss` 和 flock。下载项目后,就可以通过启动脚本运行:

git clone https://github.com/adminkk/tcp-monitor.git
cd tcp-monitor

bash tcp-monitor.sh start \
  --days 30 \
  --ports 40002,40000,11000 \
  --bind 0.0.0.0 \
  --http-port 8765

这条命令表示:同时监控三个本机端口的 TCP 已建立连接,每分钟记录一次,保留最近 30 天的数据,并在 8765 端口提供网页。

这里的端口只是示例,部署时替换成实际服务端口即可。网络允许访问后,在浏览器中打开:

http://服务器IP:8765/

启动脚本已经处理了后台运行,不需要额外添加 nohup。使用 bash tcp-monitor.sh 执行,也无需先给脚本添加执行权限。

日常管理只需要几条命令:

# 查看运行状态
bash tcp-monitor.sh status

# 停止采集
bash tcp-monitor.sh stop

# 调整参数后重新启动
bash tcp-monitor.sh restart \
  --days 7 \
  --ports 40002,40000 \
  --bind 0.0.0.0 \
  --http-port 8765

# 查看全部参数
bash tcp-monitor.sh --help

需要注意,`restart` 使用本次传入的参数和脚本默认值,不会自动记住上一次启动时的命令行参数。经常使用的配置,可以直接设置在启动脚本顶部。例如,默认监控多个端口:

PORTS="${TCP_MONITOR_PORTS:-40002,40000,11000}"

配置后,直接执行 bash tcp-monitor.sh start 即可。完整参数说明见项目的 README。

多端口监控的重点,是能够分别观察每个服务。

假设同时监控机器人通信端口、设备通信端口和其他服务端口,只看它们的合计,可能会掩盖某个端口的变化。因此,页面提供了端口下拉框,可以在“全部端口合计”和单个端口之间切换。

切换后,趋势曲线、区间末次连接数、峰值、均值及记录表都会同步更新。时间范围既可以选择最近 1 小时、6 小时、24 小时、7 天,也可以指定开始和结束时间。页面会每分钟重新读取文本,刷新时保留当前选择。

这让排查过程更具体:先看全部端口是否同时下降,再切换到单个端口,判断问题集中在哪个服务;接着缩小时间范围,对照应用日志查找原因。

采集结果默认写入:

data/tcp_connections.txt

文件采用 JSON Lines 格式,每行对应一次采样:

{"timestamp":1793923200,"state":"established","ports":[40000,40002],"count":28,"port_counts":{"40000":10,"40002":18}}

其中,`count` 是本次监控范围的连接总数,`port_counts` 保存各个端口的数量。多个端口的数据来自同一次 ss 调用,不需要每个端口分别执行一次采集。

文本格式也方便后续处理:可以直接检查原始记录,或者用其他脚本继续分析。如果服务器不方便开放网页端口,也可以下载这个文本文件,在本地打开 index.html,通过“导入文本”离线查看趋势。

对于长期运行的脚本,数据保留比“能持续写入”同样重要。

--days 30 表示滚动保留最近 30 × 24 小时的数据。程序在启动时和每次采样时都会清理过期记录,同时限制样本数量,避免反复重启不断增加记录。

按每分钟一条计算,30 天最多保留约 43201 条记录。实际文件大小随监控端口数变化,但不会在正常运行中无限累积。写入时采用临时文件加原子替换,减少网页读取到不完整记录的情况。这部分逻辑位于 History 类。

另一个容易被忽略的细节,是采集失败不能记成连接数为 0。

连接数为 0,意味着采集成功,而且确实没有符合条件的连接;如果 ss 超时或者执行失败,只能说明这次没有拿到有效结果。

因此,工具会将失败采样保存为 count: null,页面标记为缺测,并断开曲线。超过 90 秒的采样间隔也会断线,避免用一条连续折线掩盖中间的数据空缺。

监控端口发生变化时,也需要保留这种严谨性。

例如,最初只监控 40002,后来增加了 40000。假设合计数从 20 变成 35,这次变化可能来自统计范围扩大,并不代表原来的服务多了 15 条连接。

tcp-monitor 允许更换端口后继续使用原来的数据目录,但每条记录都会保留它当时的端口集合:

  • 查看单个端口时,历史中未监控该端口的时段显示为缺测。

  • 查看合计时,曲线在端口集合变化处断开,并提示统计范围发生了变化。

  • 明细和悬浮提示显示每次采样实际监控的端口。

因此,增加或减少监听端口不必再拆出一套历史文件,也能看清数据口径的变化。

最后,需要区分“TCP 连接在线”和“业务在线”。

对于机器人长连接服务,日常观察一般使用默认的 established。它统计已经建立的 TCP 连接,但不能直接等同于完成认证、心跳正常且业务可用的机器人数量。

其他状态主要用于专项排查:

状态

可以观察的问题

established

当前已建立连接数量的变化

close-wait

对端请求关闭后,本机连接是否长期未释放

time-wait

连接关闭后的等待数量及其变化

syn-recv

尚未完成握手的连接是否积累

syn-sent

本机主动建立连接时是否长期等待

all

各种 TCP 状态的总量,包括监听状态

这些参数是采样过滤条件,当前页面不会将 all 再拆成不同状态的曲线。更改 state 时,仍需使用独立的数据目录,避免混合不同状态的历史数量。

另外,一分钟一次的快照适合观察趋势,可能漏掉两次采样之间出现又结束的短暂波动。遇到秒级断连、握手异常或报文问题,还需要结合实时命令、应用日志或抓包进一步调查。

内置 HTTP 服务没有登录认证。直接绑定 0.0.0.0 时,应控制访问范围;如果只供自己查看,可以显式绑定 127.0.0.1,再通过 SSH 转发访问:

# 服务器上启动
bash tcp-monitor.sh start \
  --days 30 \
  --ports 40002,40000 \
  --bind 127.0.0.1 \
  --http-port 8765

# 自己电脑上建立转发
ssh -N -L 8765:127.0.0.1:8765 用户名@服务器地址

随后在本机浏览器打开 http://127.0.0.1:8765/。

当我们需要给几台 Linux 服务器补充 TCP 连接历史时,这样一个小工具就能留下可回看的依据:连接数什么时候变化、涉及哪些端口、持续了多久。带着明确的时间窗口再去查日志,通常比故障恢复后反复执行一次 ss 更有帮助。

项目地址:adminkk/tcp-monitor。

0

评论区