先说结论:那台机器没问题,是我的检测在说谎。

那阵子在做[七亿批量远程管理工具]的连接列表,每台机器前面挂一个状态徽章——🟢 在线、🟡 端口未开、🔴 异常,还有初始的 ❓ 未检测。某天我扫列表,看到一台平时好好的机器被标成了 🔴 异常,可它明明在跑,我 SSH 上去也是好的。

检测逻辑当时很朴素:ping 一次,加连一次端口,就出三种结果——端口通 → 在线;ping 通但端口不通 → 端口未开;ping 不通 → 异常。毛病就出在“ping 不通”这条上:包只发一次。网络偶尔抖一下丢一个包,正好端口那次也没连上,这台机器就被盖了个“异常”的戳。丢一个包就判死刑,太武断。

我去查的时候还走了段弯路。第一反应是“是不是这台机器真有问题”,隔着屏幕连着 ping 了几十下,一个包没丢,端口也通。那就怀疑是不是并发检测太多,把端口探测挤掉了;把时间窗拉长,还是偶发。最后盯着代码那行“ping 一次”才反应过来——不是机器在抖,是我只给了它一次机会。

改法是把一次改成三次:ping 重试 3 次,每次超时压到 ≤1.5 秒,间隔 300 毫秒,任意一次成功就算“通”,单次丢包不再直接判异常。代价是多花几秒,可“异常”这东西一旦误报,用户下次就不信它了,这点信任比那几秒金贵。改动落在 Utils.cs 的 NetworkHelper.CheckHost 里。

顺着状态徽章又揪出第二个毛病:没检测过的行,徽章显示的居然是“检测中”,而不是“未检测”。一开始我以为是什么状态没初始化,翻半天才发现是解析那步的问题——ParseBadge 里写的是 raw.Contains("检测"),拿它判断“是不是检测中”,可“未检测”这三个字里也含“检测”,一句话把两个状态都匹配上了,初始的“❓ 未检测”就被误读成“检测中”。改法是把判断顺序调过来,先判“未检测”,再判“检测中”。涉及 MainFormNew.cs。

顺手也把“异常”的条件确认牢了:只有 ping 不通、端口也不通,才叫异常;端口通就叫在线。这条其实一直都在,只是上面两个 bug 叠在一起,让人说不清它到底准不准。四态定死:在线 / 端口未开 / 异常 / 未检测。

回头看,这两个 bug 有个共同点——都不是“算错了”,是“话说得太绝对”:一次丢包就敢下结论,一个包含关系就敢拿去匹配。检测给的判断,用户是当依据用的,宁可多 ping 两下、多判一个分支,也别急着盖戳。

这套东西在七亿批量远程管理工具里,跟那个把内存看错的诊断报告算一个毛病的两面——一个把正常当异常,一个把 8G 看成只剩 171M。检测和报告这类“替用户看”的功能,准不准比快不快重要。想自己上手试试,七亿批量远程管理工具的教程页里有从连机器到批量检测的走法。

至于那台被误判的机器,我后来重新点了一次检测,🟢 就回来了。它本来就没病。

QQ20261009-071746.png