找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 7|回复: 0

网络巡检员云手机断网预警

[复制链接]
发表于 15 分钟前 | 显示全部楼层 |阅读模式
网络巡检员云手机断网预警

QQ截图20261109102158.png

QQ截图20261109102147.png

QQ截图20261109102135.png

  1. /**
  2. * 案例38(录像版):网络巡检员——云手机断网预警 + 延迟台账
  3. *
  4. * 题材来源:设备农场运维刚需。云手机网络一抖,刷视频任务全断流、掉线不自知,
  5. *          第二天客户问"为什么昨晚任务没跑满"——没台账说不清。本案例把
  6. *          "网络到底好不好"变成可量化:丢包率、平均延迟、DNS 能不能解析,
  7. *          每轮巡检打屏 + 落盘 CSV,长期跑就是网络质量台账。
  8. *
  9. * 录像友好增强(用户要求):
  10. *   ① 开场打"网络环境卡":本机IP/网关/DNS1/DNS2 全放出来;
  11. *   ② 每个 ping 目标逐包打一行(time=xx ms),满屏滚动有节奏;
  12. *   ③ 收工给每目标画 ASCII 延迟条(█ 长度=延迟),报告有画面感。
  13. *
  14. * 全走锤死通道(零新API):
  15. *   ping 探测 → adb.exec("ping -c N -W 2 地址")(案例30锤死:JSON包{errorMsg,success})
  16. *   本机 IP  → device.getIP()(案例37锤死)
  17. *   网关     → cat /proc/net/route 默认路由,小端十六进制转 IP
  18. *   DNS      → getprop net.dns1 / net.dns2
  19. *   DNS 验证 → 直接用域名当 ping 目标:解析不了 ping 就报错,天然测 DNS
  20. *   落盘 CSV → adb.exec sh -c echo 追加(案例37锤死写法)
  21. *   等待     → sleep.second(整秒)/ sleep.millisecond(毫秒),禁止裸 sleep()
  22. *
  23. * 写法合规:Rhino ES5,全 var、字符串拼接、函数先定义后调用、main() 末尾启动;
  24. * 节奏输出:每轮巡检前 3..2..1 倒计时,日志行间留白,方便盯屏录像。
  25. */

  26. // ========== 配置区 ==========
  27. var 巡检目标表 = [
  28.     { 名: "阿里DNS",   址: "223.5.5.5" },
  29.     { 名: "DNSPod",   址: "119.29.29.29" },
  30.     { 名: "百度(测DNS)", 址: "www.baidu.com" }
  31. ];
  32. var 巡检轮数 = 3;            // 演示 3 轮,常驻改大
  33. var 每轮ping次数 = 4;        // 每个目标 ping 4 包(逐包打屏)
  34. var 轮间隔秒 = 5;            // 两轮之间歇 5 秒
  35. var 台账目录 = "/sdcard/auto";

  36. // ========== adb 通道(案例30锤死) ==========
  37. function adb跑(命令) {
  38.     try {
  39.         var 数据 = JSON.parse(adb.exec(命令, false));
  40.         var 成 = 数据.success == null ? "" : ("" + 数据.success);
  41.         var 错 = 数据.errorMsg == null ? "" : ("" + 数据.errorMsg).trim();
  42.         return { 成: 成, 错: 错 };
  43.     } catch (e) {
  44.         return { 成: "", 错: "exec异常 " + e };
  45.     }
  46. }

  47. // ========== 节奏倒计时(整秒一律 sleep.second) ==========
  48. function 节奏倒计时(秒数, 干什么) {
  49.     for (var i = 秒数; i > 0; i--) {
  50.         printl("⏰ " + i + " 秒后:" + 干什么);
  51.         sleep.second(1);
  52.     }
  53.     printl("🎬 " + 干什么 + " —— 开始");
  54.     sleep.millisecond(400);
  55. }

  56. // ========== 网络环境卡:本机IP / 网关 / DNS ==========
  57. function 取网关() {
  58.     var r = adb跑("cat /proc/net/route");
  59.     var 行表 = ("" + r.成).split("\n");
  60.     for (var i = 0; i < 行表.length; i++) {
  61.         var 列 = ("" + 行表[i]).trim().split(/\s+/);
  62.         if (列.length < 4) continue;
  63.         if (列[1] === "00000000") {           // 目的=0.0.0.0 即默认路由
  64.             var gw = 列[2];
  65.             if (gw === "00000000") continue;
  66.             // 小端十六进制 → 点分IP
  67.             var 段 = [];
  68.             for (var j = 3; j >= 0; j--) 段.push(parseInt(gw.substr(j * 2, 2), 16));
  69.             return 段.join(".");
  70.         }
  71.     }
  72.     return "未知";
  73. }

  74. function 取DNS() {
  75.     var d1 = adb跑("getprop net.dns1");
  76.     var d2 = adb跑("getprop net.dns2");
  77.     var 一 = ("" + d1.成).trim();
  78.     var 二 = ("" + d2.成).trim();
  79.     if (一 === "") 一 = "未知";
  80.     if (二 === "") 二 = "无";
  81.     return { 主: 一, 备: 二 };
  82. }

  83. function 打网络环境卡(本机IP, 网关, dns) {
  84.     printl("┌──────── 网络环境卡 ────────");
  85.     printl("│ 本机 IP : " + 本机IP);
  86.     printl("│ 默认网关: " + 网关);
  87.     printl("│ DNS 主  : " + dns.主);
  88.     printl("│ DNS 备  : " + dns.备);
  89.     var 目标串 = [];
  90.     for (var i = 0; i < 巡检目标表.length; i++) 目标串.push(巡检目标表[i].名 + "(" + 巡检目标表[i].址 + ")");
  91.     printl("│ 探测目标: " + 目标串.join(" | "));
  92.     printl("│ 探测强度: " + 巡检轮数 + " 轮 × " + 每轮ping次数 + " 包/目标");
  93.     printl("└──────────────────────────────");
  94.     sleep.millisecond(600);
  95. }

  96. // ========== ASCII 延迟条(报告有画面感) ==========
  97. function 画条(ms) {
  98.     if (ms < 0) return "?";
  99.     var 格 = Math.max(1, Math.round(ms / 10));
  100.     if (格 > 40) 格 = 40;
  101.     var 条 = "";
  102.     for (var i = 0; i < 格; i++) 条 += "█";
  103.     return 条 + " " + ms + "ms";
  104. }

  105. // ========== ping 一个目标并解析(含逐包时间列表) ==========
  106. function ping一次(地址) {
  107.     var r = adb跑("ping -c " + 每轮ping次数 + " -W 2 " + 地址);
  108.     var 文本 = r.成;
  109.     if (文本 === "") return { 死: true, 因: r.错.slice(0, 60), 包: [] };
  110.     var 丢包 = 文本.match(/(\d+(?:\.\d+)?)% packet loss/);
  111.     if (丢包 == null) {
  112.         var 解析挂 = ("" + 文本 + r.错).match(/bad address|unresolved|Name or service/i);
  113.         return { 死: true, 因: 解析挂 == null ? "没匹配到统计行" : "DNS解析失败", 包: [] };
  114.     }
  115.     var 延迟 = 文本.match(/=\s*([\d.]+)\/([\d.]+)\/([\d.]+)/);
  116.     // 逐包:64 bytes from x: icmp_seq=1 ttl=.. time=12.3 ms
  117.     var 包 = [];
  118.     var re = /time=([\d.]+)\s*ms/g;
  119.     var m;
  120.     while ((m = re.exec(文本)) != null) 包.push(parseFloat(m[1]));
  121.     return {
  122.         死: false,
  123.         丢包率: parseFloat(丢包[1]),
  124.         平均ms: 延迟 == null ? -1 : parseFloat(延迟[2]),
  125.         最大ms: 延迟 == null ? -1 : parseFloat(延迟[3]),
  126.         包: 包
  127.     };
  128. }

  129. // ========== 单目标评级 ==========
  130. function 评级(结果) {
  131.     if (结果.死) return "❌不通";
  132.     if (结果.丢包率 > 0) return "⚠丢包" + 结果.丢包率 + "%";
  133.     if (结果.平均ms >= 300) return "🐢慢(" + 结果.平均ms + "ms)";
  134.     return "✅" + 结果.平均ms + "ms";
  135. }

  136. // ========== 台账落盘(CSV,案例37锤死写法) ==========
  137. function 补零(n) { return n < 10 ? "0" + n : "" + n; }

  138. function 台账路径() {
  139.     var d = new Date();
  140.     return 台账目录 + "/网络巡检_" + d.getFullYear() + 补零(d.getMonth() + 1) + 补零(d.getDate()) + ".csv";
  141. }

  142. function 写台账(行文本, 路径) {
  143.     var 安全 = ("" + 行文本).replace(/'/g, "’");
  144.     adb跑("sh -c "echo '" + 安全 + "' >> " + 路径 + """);
  145. }

  146. // ========== 主流程 ==========
  147. function main() {
  148.     printl("=== 案例38 网络巡检员 启动:" + 巡检轮数 + " 轮 × " + 巡检目标表.length + " 目标 ===");
  149.     sleep.millisecond(500);

  150.     // 开场:网络环境卡(IP/网关/DNS 全放出来)
  151.     节奏倒计时(3, "打网络环境卡");
  152.     var 本机IP = "未知";
  153.     try { 本机IP = device.getIP(); } catch (e) {}
  154.     var 网关 = 取网关();
  155.     var dns = 取DNS();
  156.     打网络环境卡(本机IP, 网关, dns);

  157.     var 路径 = 台账路径();
  158.     写台账("时间,目标,丢包率%,平均ms,最大ms,评级", 路径);
  159.     printl("📒 台账文件: " + 路径);
  160.     sleep.millisecond(600);

  161.     var 累计 = [];
  162.     var i0;
  163.     for (i0 = 0; i0 < 巡检目标表.length; i0++)
  164.         累计.push({ 不通: 0, 丢包总: 0, 延迟总: 0, 有效: 0 });

  165.     var d0 = new Date();
  166.     var 表头 = d0.getFullYear() + "-" + 补零(d0.getMonth() + 1) + "-" + 补零(d0.getDate());

  167.     for (var 轮 = 1; 轮 <= 巡检轮数; 轮++) {
  168.         节奏倒计时(3, "第 " + 轮 + "/" + 巡检轮数 + " 轮全网探测");
  169.         for (var i = 0; i < 巡检目标表.length; i++) {
  170.             var 目标 = 巡检目标表[i];
  171.             printl("   ▶ 探测 " + 目标.名 + " [" + 目标.址 + "]");
  172.             sleep.millisecond(300);
  173.             var r = ping一次(目标.址);

  174.             if (r.死) {
  175.                 var 时0 = new Date();
  176.                 printl("     ❌ " + r.因 + " (" + 补零(时0.getHours()) + ":" + 补零(时0.getMinutes()) + ":" + 补零(时0.getSeconds()) + ")");
  177.                 累计[i].不通++;
  178.                 var 时A = new Date();
  179.                 写台账(表头 + " " + 补零(时A.getHours()) + ":" + 补零(时A.getMinutes()) + ":" + 补零(时A.getSeconds()) +
  180.                         "," + 目标.名 + ",100,-,-," + 目标.址 + "不通(" + r.因 + ")", 路径);
  181.             } else {
  182.                 // 逐包打屏:录像滚动好看
  183.                 for (var p = 0; p < r.包.length; p++) {
  184.                     printl("     第" + (p + 1) + "包 → " + 画条(r.包[p]));
  185.                     sleep.millisecond(300);
  186.                 }
  187.                 var 评 = 评级(r);
  188.                 var 时 = new Date();
  189.                 var 时刻 = 补零(时.getHours()) + ":" + 补零(时.getMinutes()) + ":" + 补零(时.getSeconds());
  190.                 printl("     📊 小计: 丢包 " + r.丢包率 + "% | 评级 " + 评);
  191.                 sleep.millisecond(400);

  192.                 累计[i].有效++;
  193.                 累计[i].丢包总 += r.丢包率;
  194.                 if (r.平均ms >= 0) 累计[i].延迟总 += r.平均ms;
  195.                 写台账(表头 + " " + 时刻 + "," + 目标.名 + "," + r.丢包率 + "," +
  196.                         r.平均ms + "," + r.最大ms + "," + 评, 路径);
  197.             }
  198.         }
  199.         if (轮 < 巡检轮数) {
  200.             printl("   💤 歇 " + 轮间隔秒 + " 秒进下一轮");
  201.             sleep.second(轮间隔秒);
  202.         }
  203.     }

  204.     // ========== 巡检报告(带延迟条) ==========
  205.     printl("========== 📋 巡检报告(" + 巡检轮数 + " 轮均值) ==========");
  206.     var 全通 = true;
  207.     for (var j = 0; j < 巡检目标表.length; j++) {
  208.         var c = 累计[j];
  209.         var 名 = 巡检目标表[j].名;
  210.         if (c.有效 === 0) {
  211.             printl("  " + 名 + " : ❌ " + 巡检轮数 + " 轮全不通(DNS挂了/断网/被墙)");
  212.             全通 = false;
  213.             continue;
  214.         }
  215.         var 平均丢 = Math.round(c.丢包总 / 巡检轮数 * 10) / 10;
  216.         var 平均延迟 = Math.round(c.延迟总 / c.有效 * 10) / 10;
  217.         var 结论 = 平均丢 > 0 ? "⚠ 有丢包" : (平均延迟 >= 300 ? "🐢 偏慢" : "✅ 健康");
  218.         if (平均丢 > 0 || 平均延迟 >= 300) 全通 = false;
  219.         printl("  " + 名 + " : 丢包 " + 平均丢 + "% | 不通 " + c.不通 + "/" + 巡检轮数 + " 轮 → " + 结论);
  220.         printl("     延迟 " + 画条(平均延迟));
  221.     }
  222.     printl("  总体: " + (全通 ? "✅ 网络健康,任务放心挂" : "⚠ 网络有隐患,建议错峰/换线路/查DNS"));
  223.     printl("📒 台账已存: " + 路径 + "(多台设备同名文件各跑各的,收回来就是农场网络报表)");
  224.     printl("💡 报警接法:评级出现 ❌ 时,adb.exec 里 curl 一条 HTTP 到你的服务器;常驻=外层套 while+sleep.second(60)");
  225.     printl("=== 案例38 收工 ===");
  226. }

  227. // ========== 启动(Rhino ES5:函数全部定义完才调用) ==========
  228. main();
复制代码


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|

GMT+8, 2026-11-10 06:45

安卓脚本软件 · 键鼠盒子 · HID · 机械臂

快速回复 返回顶部 返回列表

随机推荐 · 热帖 / 新帖 / 随便看看

社区会员(随机展示)