自制 Ping 监控工具,助我监看网络链路疑难杂症

文章目录
文章目录
  1. 1. 当前项目的网络拓扑结构
  2. 2. 问题背景 & 原因
  3. 3. 自制网络监控脚本
  4. 4. 解决方案和优化思路

最近几天,我一直泡在客户现场,为一套出入管理系统做安装和调试。项目本身并不算特别复杂,但网络链路略长、设备层级较多,再叠加门禁前端设备对网络稳定性的敏感度,几乎把这个“小工程”变成了一次完整的网络排障实战。

在这个过程中,我发现仅靠临时敲几下 ping 命令远远不够:需要能够长期监控、按时间统计丢包、自动记录日志的“小工具”,帮我判断网络到底是偶发抖动,还是结构性不稳定。于是,就有了本文分享这个已经跑通、用着还不错的 BAT 监控小脚本。希望对你也有用~

1. 当前项目的网络拓扑结构

本次项目的系统依托园区现有网络架构,通过多级接入交换机构成一条从服务器到岗亭电脑、再到门禁前端设备的完整链路。整体设计看似规范,但只要其中某个环节出现问题,尤其是接入交换机 1 不稳定,后续所有设备便会受到连带影响。总体而言,这套网络结构属于典型的“业务分层 + VLAN 分区”模式:

  • 下层是门禁专网和办公终端网段
  • 上层是园区核心网络和服务器资源
  • 中间是三层/二层交换机级联

从后端服务器到岗亭电脑,大致链路如下:

Server 172.20.1.35
   │
   ▼
Core Network (Core Switch / Router / ...)
   │
   ▼
Access Switch 1 ── 10.255.18.21
   │
   ▼
Access Switch 2 ── 10.255.18.23
   │
   ▼
Access Switch 3 ── 10.255.18.24
   │
   ├── VLAN 107 (172.18.7.0/24)
   │        │
   │        ▼
   │     岗亭电脑 ── 172.18.7.90
   │
   └── VLAN 121 (192.168.121.0/24)
            │
            ├── 车牌识别一体机...
            │
            └── 人脸识别一体机...

2. 问题背景 & 原因

我们最初发现前端的车牌识别一体机频繁无故掉线,起初以为是供电不稳定,但进一步排查后才确认问题出在网络链路上。在服务器端持续 ping 相关设备时,可以明显看到偶发的连续掉包。经过几轮基础测试,我们最终发现:从服务器到第一台接入交换机的链路本身就存在不稳定。既然最前端链路已经开始丢包,那么后续所有依赖这条链路的设备,其网络质量只会在此基础上持续衰减,绝不可能更好…😅

对客户而言,这种情况并不是“偶发的小波动”,而是会直接影响现场体验、业务流程以及系统可信度的核心问题。因此,我需要一种更专业、更量化的方法,来准确证明这条链路的“不稳定性”,并提供可追溯的数据依据。

当然,目前仍无法完全判定导致本次网络故障的根本原因……如果各位大佬有类似经验,也请不吝分享,感激不尽…

3. 自制网络监控脚本

一直盯着命令行窗口看 ping 输出既不现实也不专业,因此我干脆写了一个小工具,用 Windows 批处理脚本做了一套“简易 Ping 监控系统”。它不华丽,但非常实用。🛠️

3.1 工具设计目标 🎯

在写这个 BAT 的时候,我给自己定了几个简单但刚好够用的目标:

  • 能够长时间稳定运行,不需要人为值守
  • 支持用户自定义目标 IP,并且有默认值(当前网关,实在取不到就用 8.8.8.8)
  • 对用户输入的 IPv4 做基础校验,避免输错 IP 浪费时间
  • 每秒 ping 一次,按小时做统计汇总:总次数、超时次数、丢包率
  • 自动把小时统计结果写入日志文件,方便回看历史情况
  • 按 Ctrl + C 时可以正常结束,由系统提示按 Y 退出、按 N 继续,让行为可控

简而言之,就是做一个“比裸 ping 更聪明一点”的小监控工具。

3.2 代码核心亮点 💡

虽然整个 BAT 文件有点长,但逻辑并不复杂,可以拆成几个关键点来理解。

1)自动获取默认网关,作为默认监测目标

脚本启动时,会尝试通过 route print 和 wmic 等方式获取当前网络默认网关,获取不到再回退到 8.8.8.8:

  • 优先用 Get-NetRoute0.0.0.0/0 的 NextHop
  • 如果失败,则用 route print 解析默认路由
  • 再不行就用 wmic nicconfigDefaultIPGateway
  • 最终兜底:TARGET_DEFAULT=8.8.8.8

这样,在大多数现场环境里,哪怕用户不输入任何 IP,直接回车也能用“当前网关”来做监控,非常契合调试场景。

自制 Ping 监控工具,助我监看网络链路疑难杂症
会自动检查网卡设置,并设置默认目标地址为网络网关

2)用户输入 + IPv4 合法性校验

为了避免输错 IP,脚本对输入做了简单的 IPv4 校验:

  • 必须是四段,用点分隔
  • 每一段必须是 0–255 之间的纯数字
  • 最多允许三次错误,超过次数就直接退出,避免误操作

3)按小时统计丢包并写入日志

脚本内部维护了几个计数器:totaltimeout 等,每 ping 一次就累加一次总数,超时就累加一次超时数,并根据当前小时与上一轮比较,一旦跨小时就自动结算上一小时的统计结果。日志文件按日期和目标 IP 命名,例如:C:\ping_logs\Ping_10.255.18.21_20251121.log,这对回溯某一天、某一小时是否出现过明显丢包非常有帮助。最终的脚本如下,你可以另存为 PingLogger.bat 文件,或者从下面下载。

自制 Ping 监控工具,助我监看网络链路疑难杂症
点号代表正常,X 号代表断线,后面是异常统计,自动生成的日志名称命名清晰
自制 Ping 监控工具,助我监看网络链路疑难杂症
每个钟头会显示一次统计,而这条统计会写进日志文件中。上图中,因为我电脑中间休眠了,故数据量较少
@echo off
setlocal EnableDelayedExpansion

:: ==================== Init default gateway as TARGET_DEFAULT ====================
call :GetDefaultGateway

:: ==================== Intro ====================
cls
echo Ping monitor utility
echo - Send one ping per second to target IP
echo - Show hourly packet loss summary on screen and in log file
echo - Log files are saved under C:\ping_logs
echo.
echo Copyright (c) Kevin's, www.shephe.com
echo.


:: ==================== Ask user for target IP ====================
call :AskTargetIP
if %errorlevel% geq 1 goto :EOF

:: ==================== Main config ====================
set "LOGDIR=C:\ping_logs"

:: Create folder if needed
if not exist "%LOGDIR%" md "%LOGDIR%" >nul 2>&1

:: Get today and current hour via PowerShell (robust, no wmic needed)
for /f "delims=" %%a in ('powershell -NoProfile -Command "Get-Date -Format yyyyMMdd" 2^>nul') do set "TODAY=%%a"
for /f "delims=" %%a in ('powershell -NoProfile -Command "Get-Date -Format HH" 2^>nul') do set "CURRENT_HOUR=%%a"

if not defined TODAY (
    echo Error: Could not get date. Using fallback.
    for /f "tokens=2 delims==" %%i in ('wmic os get localdatetime /value 2^>nul') do set dt=%%i
    if defined dt (
        set TODAY=!dt:~0,4!!dt:~4,2!!dt:~6,2!
    ) else (
        set TODAY=%date:~10,4%%date:~4,2%%date:~7,2%
    )
)
if not defined CURRENT_HOUR set CURRENT_HOUR=%time:~0,2%

set "LOGFILE=%LOGDIR%\Ping_%TARGET%_%TODAY%.log"

set total=0
set timeout=0

cls
echo.
echo ==========================================================
echo    Monitoring %TARGET%  (hourly loss summary)
echo    Log file: %LOGFILE%
echo    Press Ctrl+C to stop anytime
echo ==========================================================
echo.
echo [%TODAY% %time:~0,8%] Monitoring started for %TARGET% >> "%LOGFILE%"

:loop
set /a total=total+1

:: Ping once, 1-sec timeout
ping -n 1 -w 1000 %TARGET% >nul 2>&1
if errorlevel 1 (
    set /a timeout=timeout+1
    set MARK=X
) else (
    set MARK=.
)

:: Live display (break line every 60 pings to avoid spam)
set /a mod=total %% 60
if !mod!==0 (
    <nul set /p ="!MARK! (!total!/!timeout!)   "
    echo.
) else (
    <nul set /p ="!MARK! "
)

:: Refresh current hour
for /f "delims=" %%h in ('powershell -NoProfile -Command "Get-Date -Format HH" 2^>nul') do set "THIS_HOUR=%%h"
if not defined THIS_HOUR set THIS_HOUR=%time:~0,2%

:: Hour change? Summarize previous hour
if not "!THIS_HOUR!"=="!CURRENT_HOUR!" (
    if !total! gtr 0 (
        set /a loss_rate=timeout*100/total
    ) else (
        set loss_rate=0
    )
    set summary=[%TODAY% !CURRENT_HOUR!:00-!CURRENT_HOUR!:59] Total:!total!  Timeout:!timeout!  Loss:!loss_rate!%%

    echo.
    echo -----------------------------------------------------------
    echo !summary!
    echo -----------------------------------------------------------
    echo !summary! >> "%LOGFILE%"

    :: Midnight? Update for new day
    if "!CURRENT_HOUR!"=="23" if "!THIS_HOUR!"=="00" (
        :: Get new today
        for /f "delims=" %%a in ('powershell -NoProfile -Command "Get-Date -Format yyyyMMdd" 2^>nul') do set "NEW_TODAY=%%a"
        if not defined NEW_TODAY (
            for /f "tokens=2 delims==" %%i in ('wmic os get localdatetime /value 2^>nul') do set dt=%%i
            if defined dt (
                set NEW_TODAY=!dt:~0,4!!dt:~4,2!!dt:~6,2!
            ) else (
                set NEW_TODAY=%date:~10,4%%date:~4,2%%date:~7,2%
            )
        )
        set TODAY=!NEW_TODAY!
        set "LOGFILE=%LOGDIR%\Ping_%TARGET%_%TODAY%.log"
        echo [%TODAY% %time:~0,8%] Monitoring started for %TARGET% >> "%LOGFILE%"
    )

    :: Reset
    set total=0
    set timeout=0
    set CURRENT_HOUR=!THIS_HOUR!
)

:: ~1 second delay (timeout preferred, fallback to ping)
timeout /t 1 /nobreak >nul 2>&1
if errorlevel 1 ping -n 2 127.0.0.1 >nul 2>&1
goto loop

goto :EOF

:: ==========================================================
:: Subroutine: GetDefaultGateway -> TARGET_DEFAULT
:: Try PowerShell, then route print, then WMIC, fallback 8.8.8.8
:: ==========================================================
:GetDefaultGateway
set "TARGET_DEFAULT="

:: Try PowerShell Get-NetRoute (newer systems)
for /f "usebackq tokens=* delims=" %%g in (`
    powershell -NoProfile -Command "(Get-NetRoute -DestinationPrefix '0.0.0.0/0' ^| Sort-Object RouteMetric ^| Select-Object -First 1).NextHop" 2^>nul
`) do (
    if not "%%g"=="" set "TARGET_DEFAULT=%%g"
)

:: Fallback: parse 'route print' default route (works on most Windows)
if not defined TARGET_DEFAULT (
    for /f "tokens=1-3" %%a in ('route print ^| findstr "0.0.0.0  0.0.0.0"') do (
        if not defined TARGET_DEFAULT (
            if "%%a"=="0.0.0.0" if "%%b"=="0.0.0.0" set "TARGET_DEFAULT=%%c"
        )
    )
)

:: Fallback: WMIC default gateway
if not defined TARGET_DEFAULT (
    set "gw="
    for /f "tokens=2 delims==" %%g in ('wmic nicconfig where "IPEnabled=TRUE and DefaultIPGateway is not null" get DefaultIPGateway /value 2^>nul ^| find "="') do (
        set "gw=%%g"
    )
    if defined gw (
        set "gw=!gw:{=!"
        set "gw=!gw:}=!"
        for /f "tokens=1 delims=," %%x in ("!gw!") do set "TARGET_DEFAULT=%%x"
    )
)

:: Final fallback: use 8.8.8.8
if not defined TARGET_DEFAULT set "TARGET_DEFAULT=8.8.8.8"

exit /b

:: ==========================================================
:: Subroutine: AskTargetIP -> TARGET
:: Validate IPv4, allow 3 attempts total
:: ==========================================================
:AskTargetIP
set "attempt=0"

:ask_loop
set /a attempt+=1
echo.
set /p "TARGET=Please enter target IPv4 address (default: %TARGET_DEFAULT%): "
if "%TARGET%"=="" set "TARGET=%TARGET_DEFAULT%"

call :ValidateIPv4 "%TARGET%" valid
if /i "%valid%"=="true" (
    echo Target IP accepted: %TARGET%
    exit /b 0
) else (
    echo Invalid IPv4 address: %TARGET%
    if %attempt% GEQ 3 (
        echo Too many invalid attempts. Exiting.
        exit /b 1
    ) else (
        echo Please try again.
        goto ask_loop
    )
)

:: ==========================================================
:: Subroutine: ValidateIPv4 "%1" -> result in %2 (true/false)
:: ==========================================================
:ValidateIPv4
setlocal EnableDelayedExpansion
set "ip=%~1"
set "ok=true"

set "o1="
set "o2="
set "o3="
set "o4="

for /f "tokens=1-4 delims=." %%a in ("%ip%") do (
    set "o1=%%a"
    set "o2=%%b"
    set "o3=%%c"
    set "o4=%%d"
)

:: Must have four octets
if not defined o1 set "ok=false"
if not defined o2 set "ok=false"
if not defined o3 set "ok=false"
if not defined o4 set "ok=false"

:: Rebuild address to ensure exactly 3 dots and no extra text
if "!ok!"=="true" (
    set "rebuild=!o1!.!o2!.!o3!.!o4!"
    if /i not "!rebuild!"=="!ip!" set "ok=false"
)

:: Check numeric and range 0-255 for each octet
if "!ok!"=="true" (
    for %%O in (!o1! !o2! !o3! !o4!) do (
        if "%%O"=="" set "ok=false"
        for /f "delims=0123456789" %%Z in ("%%O") do (
            if not "%%Z"=="" set "ok=false"
        )
        if "!ok!"=="true" (
            if %%O LSS 0 set "ok=false"
            if %%O GTR 255 set "ok=false"
        )
    )
)

endlocal & set "%2=%ok%"
exit /b

实用网络质量监测脚本 PingLogger.bat.zip

已经回复?刷新

3.3 实战中的使用方式 🧪

在这次门禁项目中,我主要是这样用这个脚本的:

  • 在服务器上,以接入交换机 1(10.255.18.21)为目标跑长期监控,观察核心到接入层的稳定性
  • 必要时,把目标改成接入交换机 2、3,甚至是岗亭电脑 IP,用来判断问题到底出在哪个“段落”
  • 结合日志中的小时丢包率,能看到是否有某些时间段(比如工作高峰、夜间备份时)丢包特别明显

相比肉眼盯着 ping 窗口,这个小工具的优势在于:

  • 可以丢给客户或值班人员,让他们开着窗口就行
  • 只要事后拿到日志,就能快速定位“问题大概在什么时候开始、持续了多久”

4. 解决方案和优化思路

有了监控数据,后面的工作就从“凭感觉猜”变成了“拿数据说话”。以Ping_172.20.1.33_20251121.log为例,可以从日志直观地分析出时间段内两个设备之间的网络质量情况。

[20251121 15:15:35] Monitoring started for 172.20.1.33 
[20251121 15:00-15:59] Total:2051  Timeout:615  Loss:29% 
[20251121 16:00-16:59] Total:3417  Timeout:183  Loss:5% 
[20251121 17:00-17:59] Total:3538  Timeout:62  Loss:1% 
[20251121 18:00-18:59] Total:3528  Timeout:71  Loss:2% 
[20251121 19:00-19:59] Total:3567  Timeout:33  Loss:0% 

4.1 硬件与物理链路排查 🔍

针对接入交换机 1 到后续设备这段链路,我会优先检查:

  • 上联光模块、网线、水晶头是否存在接触不良、氧化或质量问题
  • 交换机端口是否有错误包统计(如 CRC、input error 等,需在设备上查看)
  • 端口速率、双工模式是否一致,是否有“协商不一致”导致性能抖动

对于弱电工程而言,物理层的小故障往往最“隐蔽”、也最容易被忽视……遗憾的是,即使我们心里很清楚问题通常就藏在这些基础环节里,却依然难以完全避免。更无奈的是,绝大多数此类问题最终都指向同一个根源——施工不规范。

4.2 配置与拓扑优化 🧩

在排除物理问题之后,若还未解决故障,那么重点就回到配置和拓扑本身:

  • 检查 trunk 口 VLAN 允许列表是否正确,避免不必要的广播、组播泛滥
  • 查看是否存在冗余链路却没有正确启用生成树(STP),防止广播风暴
  • 合理规划 VLAN 之间的三层转发路径,保证门禁专网数据不过多绕路
  • 在条件允许的情况下,适度“拉近”服务器与门禁专网之间的网络距离,减少不必要的跳数

这些工作都可以结合 BAT 工具的监控结果,一边调、一边看丢包和延迟是否明显改善...

4.3 持续监控与后续计划 📊

这次写出来的 BAT 小工具,本来只是为了应付当前项目,但实际用下来体验不错,也让我意识到:

  • 对于类似门禁、监控、楼宇自控这类弱电系统,网络质量就是“生命线”
  • 一个轻量级的监控脚本,比起直接上大而全的监控平台,反而更适合在现场快速部署
  • 未来可以继续完善,比如加一个简单的图形展示(配合日志导出到其他工具)、或者加入多目标轮询等功能

接下来我也会把这次的脚本和调试过程整理好,发布在自己的博客 Kevin's Space 上,既是给自己做个备忘,也是给后来者多提供一个排障思路。不得不说,AI 真好啊~

「自制 Ping 监控工具,助我监看网络链路疑难杂症」有 8 条评论
  • 的头像
    obaby
    11/22/2025 at 21:09

    网络故障解决的确比较麻烦。

    • 的头像
      Kevin
      11/29/2025 at 22:21

      是的呢,
      到目前都还没解决…估计是地址冲突

  • 的头像
    acevs
    11/22/2025 at 15:56

    b站看过一些酒店监控路由排障的说不定有点帮助,这个某一段问题,也至少三个东西有问题,端和端,还有有线网络。你这还有vlan.

    • 的头像
      Kevin
      11/29/2025 at 22:20

      真正遇上的时候,就比这几个要复杂多了。。。

  • 游钓四方
    11/22/2025 at 01:41

    我感觉写 shell 这类流程化的脚本比前后端代码还让我头疼,用 Ai 很容易解决

    • 的头像
      Kevin
      11/29/2025 at 22:19

      嗯,我不是专业的~~
      只能是一遍一遍试了

  • 水拍石
    11/21/2025 at 22:03

    这个看着好复杂,刚开始以为是公网,想着1秒ping一次怎么不会被防火墙拦截,后来才注意到是专网。没有接触过这种网络,看ping第一个想到的就是我的阿里云,乡巴佬思维。

    • 的头像
      Kevin
      11/29/2025 at 22:06

      倒是不复杂
      AI确实是给了我们极大便利~

发表评论

请输入关键词…