运维工程师接到用户报障的时候,一般的流程是:问清楚是上不了网还是打不开某个系统、什么时候开始的、有没有改过什么。然后自己去测试:ping网关、ping目标、查DNS、traceroute……这些步骤其实每次都差不多。
与其每次手动重复,不如写一个脚本,输入目标IP或域名,自动跑完一整套诊断流程,生成一份报告。用Python实现不难,主要用到subprocess来调用系统命令:
importsubprocess
importsocket
importsys
fromdatetimeimportdatetime
defrun_cmd(cmd, timeout=5):
"""执行系统命令,返回输出内容,超时返回None"""
try:
result=subprocess.run(
cmd,
shell=True,
capture_output=True,
text=True,
timeout=timeout,
encoding='utf-8',
errors='ignore'
)
returnresult.stdout.strip() ifresult.stdoutelseresult.stderr.strip()
exceptsubprocess.TimeoutExpired:
return"[超时]"
exceptExceptionase:
returnf"[错误: {e}]"
defdiagnose(target):
"""对目标执行完整网络诊断"""
print(f"\n{'='*60}")
print(f"网络诊断报告 - 目标: {target}")
print(f"诊断时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'='*60}\n")
# 1. DNS解析
print("【1. DNS解析测试】")
try:
ip=socket.gethostbyname(target)
print(f" 域名 {target} 解析成功 -> {ip}")
exceptsocket.gaierrorase:
print(f" 域名 {target} 解析失败: {e}")
print(" (无法解析,跳过后续IP层检查)\n")
return
# 2. Ping测试
print("\n【2. Ping测试(4次)】")
ping_result=run_cmd(f"ping -n 4 {target}", timeout=10)
# 取最后几行输出
lines=ping_result.split('\n')
forlineinlines[-5:]:
ifline.strip():
print(f" {line}")
# 3. 端口检测
print("\n【3. 常用端口检测】")
ports= {22: "SSH", 23: "Telnet", 80: "HTTP", 443: "HTTPS",
3389: "RDP", 3306: "MySQL", 5432: "PostgreSQL"}
forport, serviceinports.items():
sock=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
result=sock.connect_ex((target, port))
status="开放"ifresult==0else"关闭"
print(f" {port}/tcp ({service}): {status}")
sock.close()
# 4. Traceroute
print("\n【4. Traceroute路径】")
trace_cmd="tracert -d -h 15"ifsys.platform=="win32"else"traceroute -m 15"
trace_result=run_cmd(f"{trace_cmd}{target}", timeout=15)
forlineintrace_result.split('\n')[:15]:
ifline.strip():
print(f" {line}")
# 5. 汇总
print("\n【5. 初步判断】")
if"无法访问目标主机"inping_resultor"请求超时"inping_result:
print(" 可能原因:")
print(" - 目标主机不在线或防火墙拦截了ICMP")
print(" - 网络路径存在丢包或阻塞")
print(" - 检查该IP在网络路径上是否有ACL拦截")
elif"来自 "inping_resultand"的回复: 字节="inping_result:
print(" 基本连通性正常。")
if"开放"instr(ports):
print(" 注意以下端口开放,请确认是否需要:")
else:
print(" 所有检测端口均关闭,如业务不通请检查服务是否启动。")
print(f"\n{'='*60}")
print("诊断完成。如需进一步排查,请提供以上报告。\n")
if__name__=="__main__":
iflen(sys.argv) >1:
target=sys.argv[1]
else:
target=input("请输入要诊断的目标(IP或域名): ").strip()
iftarget:
diagnose(target)
else:
print("未输入目标,退出。")

运行效果:
============================================================
网络诊断报告 - 目标: www.example.com
诊断时间: 2025-05-14 10:30:15
============================================================
【1. DNS解析测试】
域名 www.example.com 解析成功 -> 203.0.113.10
【2. Ping测试(4次)】
正在 Ping www.example.com [203.0.113.10] 具有 32 字节的数据:
来自 203.0.113.10 的回复: 字节=32 时间=15ms TTL=54
来自 203.0.113.10 的回复: 字节=32 时间=14ms TTL=54
来自 203.0.113.10 的回复: 字节=32 时间=15ms TTL=54
来自 203.0.113.10 的回复: 字节=32 时间=14ms TTL=54
www.example.com 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失)
【3. 常用端口检测】
22/tcp (SSH): 关闭
23/tcp (Telnet): 关闭
80/tcp (HTTP): 开放
443/tcp (HTTPS): 开放
...
【4. Traceroute路径】
1 <1 ms <1 ms <1 ms 192.168.1.1
2 8 ms 7 ms 7 ms 10.0.0.1
3 14 ms 15 ms 14 ms 203.0.113.10
============================================================
诊断完成。如需进一步排查,请提供以上报告。
实际工作中,用户报障的时候直接把这个报告发过来,比用户在电话里描述"网有点慢"有用得多。DNS解析成不成、Ping通不通、延迟多少毫秒、端口开没开、路由跳了几跳,全都一目了然。
有一点要提醒:Windows的ping命令参数是-n,Linux/macOS是-c。脚本里用sys.platform判断了操作系统,但traceroute的参数差异更大,Linux上默认是UDP方式探测,有些路由器会丢UDP包导致路径看起来不完整。Windows上的tracert用的是ICMP,跟实际路由更接近一点。混用两个系统的时候要注意这个差异。
诊断步骤还可以根据不同报障场景灵活组合。我把常见场景的对应检查项整理了一下:
| 报障场景 | 优先检查项 | 次优先 |
|---|
| "网断了" | Ping网关 → Ping外网 → DNS | 端口检测 |
| "某个系统打不开" | DNS解析 → Ping目标 → 端口检测 | Traceroute |
| "网速很慢" | Ping延迟 → 端口检测 | Traceroute看跳数 |
| "间歇性断线" | 多次Ping看丢包率 → Traceroute | DNS解析一致性 |
这个脚本最方便的地方是,命令行传参就能用:python diagnose.py www.example.com,不需要交互输入,适合集成到工单系统里,用户报障的时候自动触发。