# -*- coding: utf-8 -*- r'''长时间观察公网可用率 —— 这才是判断"稳不稳"的正确方法。 我之前只测了 15~25 次就连着说"可用率 100%",太草率了。 用户早上打开就撞上 Error 1033 —— 说明**间断性掉线**, 短样本根本看不出来。 这个脚本跑 10 分钟,每 3 秒一次,统计: * 总可用率 * 连续失败的最长时长(这个最要命:用户点进去就是白页) * 失败的时间分布(是零星抖动还是成片断) ''' from __future__ import annotations import statistics import sys import time import urllib.error import urllib.request URL = "https://relay.xxmxxs.top/v1/health" HEADERS = {"User-Agent": "LanRemote/1.4.0"} DURATION = 600 # 观察 10 分钟 INTERVAL = 3 # 每 3 秒一次 def probe(timeout: float = 12.0) -> tuple: """返回 (是否成功, 耗时秒, 状态码或错误名)。""" start = time.perf_counter() try: with urllib.request.urlopen( urllib.request.Request(URL, headers=HEADERS), timeout=timeout) as resp: resp.read() ok = resp.status == 200 return ok, time.perf_counter() - start, str(resp.status) except urllib.error.HTTPError as exc: return False, time.perf_counter() - start, "HTTP%d" % exc.code except Exception as exc: # noqa: BLE001 return False, time.perf_counter() - start, exc.__class__.__name__ def main() -> int: print(" 观察 %d 分钟,每 %d 秒一次" % (DURATION // 60, INTERVAL)) print() total = ok_count = 0 times = [] failures = [] streak = 0 worst_streak = 0 worst_start = None current_start = None deadline = time.time() + DURATION while time.time() < deadline: ok, elapsed, note = probe() total += 1 if ok: ok_count += 1 times.append(elapsed) streak = 0 current_start = None else: failures.append((time.strftime("%H:%M:%S"), note)) if streak == 0: current_start = time.time() streak += 1 if streak > worst_streak: worst_streak = streak worst_start = current_start # 每分钟报一次进度 if total % 20 == 0: print(" 已测 %3d 次,成功 %3d,失败 %2d" % (total, ok_count, total - ok_count)) time.sleep(INTERVAL) print() print(" ================ 结果 ================") rate = ok_count / total * 100 if total else 0 print(" 样本 %d 次(约 %d 分钟)" % (total, DURATION // 60)) print(" 可用率 %.1f%% (%d/%d)" % (rate, ok_count, total)) if times: print(" 成功时延迟 中位 %.0f ms 最快 %.0f ms 最慢 %.0f ms" % (statistics.median(times) * 1000, min(times) * 1000, max(times) * 1000)) if failures: span = worst_streak * INTERVAL print(" **最长连续失败 %d 次(约 %d 秒)**" % (worst_streak, span)) if worst_start: print(" 开始于 %s" % time.strftime("%H:%M:%S", time.localtime(worst_start))) print(" 失败明细(最多列 20 条):") for stamp, note in failures[:20]: print(" %s %s" % (stamp, note)) else: print(" 全程没有失败") print() print(" 判读:") if rate >= 99.5: print(" ≥99.5% —— 可以接受") elif rate >= 97: print(" 97~99.5% —— 有抖动,用户偶尔会遇到打不开") else: print(" <97% —— **不稳定**,必须查根因(用户会经常撞上 Error 1033)") return 0 if __name__ == "__main__": sys.exit(main())