使用 Ping 类前须处理超时与权限:Linux/macOS 需 cap_net_raw 权限,timeout 单位为毫秒且不包含 DNS 解析;DNS 失败直接抛异常;推荐用 SendPingAsync(),仅 Status 和 RoundtripTime 可信;单次 ping 不可靠,需重试聚合;ICMP 被屏蔽时可用 TCP 连接探测替代。

用 Ping 类发 ICMP 请求前必须处理超时和权限问题
Windows 上默认允许普通用户发 ICMP 包,但 .NET 6+ 在 Linux/macOS 需要 cap_net_raw 权限,否则会抛出 Operation not permitted 错误。超时设置不生效是高频坑——Ping.Send() 的 timeout 参数单位是毫秒,传 1000 是 1 秒,不是 1000 秒;且该超时只控制单次 ICMP 请求,不包含 DNS 解析耗时。
- DNS 解析失败(如主机名不存在)会直接抛
System.Net.NetworkInformation.PingException,不会等 timeout - 建议统一用异步方法
Ping.SendPingAsync(),避免线程阻塞;同步方法在高并发下容易堆积线程 - Linux 下若没授予权限,可临时用
sudo setcap cap_net_raw+ep $(readlink -f $(which dotnet))(仅开发调试,生产环境应改用非 ICMP 方案)
Ping.SendPingAsync() 返回值里真正有用的只有 Status 和 RoundtripTime
PingReply 对象看着字段多,实际能信的就两个:Status == IPStatus.Success 才算通;RoundtripTime 是毫秒级整数,别拿它算平均延迟——单次 ping 噪声大,真要测延迟得自己发多次、过滤丢包再统计。
-
Address字段可能为空(比如 DNS 解析成功但 ping 失败),不能当主机 IP 用 -
Buffer是返回的原始字节,除非你真要解析 ICMP payload,否则忽略 - 如果目标禁 ICMP(如云服务器默认关 ping),
Status会是TimedOut或DestinationHostUnreachable,不代表网络断了,只是被策略拦了
检测“是否在线”不能只靠一次 Ping.SendPingAsync()
单次 ping 成功率低得离谱:丢包、瞬时路由抖动、防火墙随机拦截都会导致误判。真实场景必须做重试 + 状态聚合。
- 至少发 3 次,容忍 1 次失败;用
Task.WhenAll()并发发,别串行等 3 秒 - 别用
Thread.Sleep()做间隔,用await Task.Delay()配合取消令牌防卡死 - 如果连续 3 次都
Status != IPStatus.Success,才认为“不可达”;中间穿插成功,说明链路不稳定,不是彻底下线
替代方案:当 Ping 不可用或不准时,用 TCP 连接试探更靠谱
ICMP 被屏蔽太常见,而多数服务至少开一个 TCP 端口(如 HTTP 的 80/443、SSH 的 22)。用 TcpClient.ConnectAsync() 测端口通不通,反而更贴近“服务是否可用”这个业务目标。
- 连接超时设 1500ms 比 ping 的 1000ms 更合理,TCP 握手比 ICMP 复杂
- 注意别对
localhost或内网地址盲目信任——容器网络、防火墙规则可能让本地连得上,外部连不上 - 如果目标是网站,直接发 HEAD 请求比 ping + tcp 更准,但要处理证书、重定向、CDN 回源等问题,复杂度陡增


















