Skip to content

网络工具例程 6:周期 Ping 多个目标(定时器 + net.ping) ​

这一页只讲这一个例程。同组其余例程、以及这个库的函数说明都在 05-05-net。

适用:同上 | 依赖模块:net timer | 难度:★☆☆

场景:同时盯着两个目标的连通性——比如本地网关(内网通不通)和公网站点(外网通不通),各用一个 5 秒定时器周期探测。

完整代码(可直接下载运行):

lua
-- 每 5 秒探一次本地网关
timeobj = timer.start(5000, function()
    net.ping("192.168.1.1", function(message)
        print(message)
    end)
end)

-- 每 5 秒探一次公网(域名也行,会自动 DNS 解析)
timeobj2 = timer.start(5000, function()
    net.ping("www.baidu.com", function(message)
        print(message)
    end)
end)

实际运行会按目标逐个打印(公网偶尔丢首包,所以可能先看到一次超时,下一轮又通了):

text
来自 192.168.1.1 的回复: 时间=11.44ms TTL=64
ping www.baidu.com (103.235.46.115) 失败: 请求超时
来自 www.baidu.com (103.235.46.115) 的回复: 时间=311.75ms TTL=47

要点:

  • net.ping 必须传 2 个参数:目标(IP 或域名)+ 结果回调。
  • 回调收到的是已格式化的中文结果串("来自 … 的回复" 或 "ping … 失败: …"),不是结构化数值,要判连通就用 msg:match("回复")。
  • 域名解析失败也走这个回调,和超时一样在串里给出原因。
  • 周期调用是安全的:net.ping 现已改为异步(worker 线程里做阻塞 ping,结果通过消息泵回主线程、在 Lua 线程里用回调返回),不会卡住您的 Lua 主线程。每次 ping 都用自己短生命周期的 socket、用完即关(RAII 析构关闭),即使定时器密集触发也不会泄漏,可放心长期挂定时器跑。

验证方法:

  1. 能上内/外网时,两个定时器都打印"回复"。

  2. 拔掉网线或网关断电,对应那条变成"失败: 请求超时",另一条不受影响。

  3. 确认无 socket 泄漏:反复触发 ping 后设备仍能正常响应、不重启,就说明用完即关成立(每次 ping 都用自己的短生命周期 socket,函数返回即释放)。 如果手上是调试版固件,还能直接读计数器核对:

    lua
    for i = 1, 200 do
        net.ping("127.0.0.1", function() end)
    end
    local s = net.ping_stats()          -- 返回 {created=累计建 socket 次数, closed=累计关 socket 次数}
    print(s.created, s.closed)          -- 两者相等即无泄漏

    net.ping_stats() 只在调试版固件里存在,出厂的正式固件调用它会报 attempt to call a nil value。 另外它返回的是表,print(net.ping_stats()) 只会打出 table: 0x…,要取 created / closed 两个字段来看。

注意事项:

  • 回调结果不能直接当数值比较,要用 match("回复") 之类判断。
  • net.ping 不再阻塞主线程(已改为异步):您调用它后立即返回,结果稍后由回调给出;底层 worker 单次 ping 仍最多等 5 秒超时,但那 5 秒发生在 worker 线程里,不占主线程。多个定时器并发 ping 也安全;只是若短时间内堆积太多 ping,会同时开多个短生命周期 socket,建议定时器间隔 ≥ 5 秒,避免瞬时占用过多。

LPPLC 工业物联网云平台 · 软硬件与云平台全栈自研