B2B网络软件

标题: WebSocket调试okhttp版 [打印本页]

作者: YYPOST群发软件    时间: 1 小时前
标题: WebSocket调试okhttp版

WebSocket调试okhttp版
WebSocket调试okhttp版 B2B网络软件

  1. /**
  2. * WebSocket 屏幕截图传输 - 本地调试版(okhttp3 版)
  3. *
  4. * 配套 WebSocket测试服务器.py 使用
  5. *
  6. * 使用方法:
  7. *   
  8. *    确认下面 serverUrl 里的 IP 是 PC 的局域网 IP
  9. *  手机和 PC 在同一 WiFi 局域网
  10. *  AIWROK 里运行本脚本
  11. *
  12. * 本次使用 okhttp3 的 WebSocketListener(非 AIWROK 原生 websocket 对象)
  13. * 已在 AIWROK v3.7.81 实际跑通
  14. */

  15. // ========== 导入 okhttp3(AIWROK 自带这些 Java 类) ==========
  16. importClass(Packages.okhttp3.OkHttpClient);
  17. importClass(Packages.okhttp3.Request);
  18. importClass(Packages.okhttp3.WebSocketListener);
  19. importClass(Packages.java.util.concurrent.TimeUnit);



  20. print.log("===== WebSocket 屏幕截图传输(okhttp3 版)开始 =====");

  21. // ========== 配置 ==========
  22. var config = {
  23.     serverUrl: "192.168.10.107:8886",   // ← 改成 PC 局域网 IP:端口
  24.     screenshotInterval: 5000,            // 截图间隔(毫秒)
  25.     reconnectInterval: 2500,              // 断线重试间隔(毫秒)
  26.     maxReconnectAttempts: 12,             // 最多重试次数
  27.     connectTimeoutSec: 15,                // 握手超时(秒)
  28.     readTimeoutSec: 30,                   // 读超时(秒)
  29.     runDuration: 30000                    // 脚本总运行时长(毫秒)
  30. };

  31. // ========== 全局状态 ==========
  32. var okHttpClient = null;     // OkHttpClient
  33. var webSocket = null;        // 当前 WebSocket 对象
  34. var timer = null;            // 定时器
  35. var state = {
  36.     connected: false,        // 是否已连接
  37.     err: null,              // 最近错误
  38.     closeReason: null,      // 关闭原因
  39.     reconnectCount: 0,       // 已重连次数
  40.     saveDir: "",            // 由服务器 WELCOME 带出
  41.     saveUrlPrefix: "",      // file:/// 前缀
  42.     totalSent: 0,           // 已尝试发送的图片数
  43.     totalConfirmed: 0       // 服务器确认收到的图片数
  44. };

  45. // ========== 工具:解析服务器结构化消息 ==========
  46. function parseServerMessage(rawStr) {
  47.     if (typeof rawStr !== "string") { try { rawStr = String(rawStr); } catch (e) { rawStr = "" + rawStr; } }
  48.     var result = { type: "UNKNOWN", raw: rawStr };
  49.     if (rawStr.indexOf("WELCOME|") === 0) {
  50.         result.type = "WELCOME";
  51.         var parts = rawStr.split("|");
  52.         result.id = parts[1] || "";
  53.         for (var i = 2; i < parts.length; i++) {
  54.             var idx = parts[i].indexOf("=");
  55.             if (idx > 0) result[parts[i].substring(0, idx)] = parts[i].substring(idx + 1);
  56.         }
  57.     } else if (rawStr.indexOf("IMG_SAVED|") === 0) {
  58.         result.type = "IMG_SAVED";
  59.         var p = rawStr.split("|");
  60.         result.seq = p[1] || "";
  61.         result.sizeTxt = p[2] || "";
  62.         result.absPath = p[3] || "";
  63.         result.fileUrl = p[4] || "";
  64.     } else if (rawStr.indexOf("IMG_FAIL|") === 0) {
  65.         result.type = "IMG_FAIL";
  66.     } else if (rawStr.indexOf("ECHO|") === 0) {
  67.         result.type = "ECHO";
  68.         result.text = rawStr.substring("ECHO|".length);
  69.     }
  70.     return result;
  71. }

  72. // ========== 释放资源(每次重连前清理旧 client) ==========
  73. function shutdownClient() {
  74.     if (webSocket) {
  75.         try { webSocket.close(1000, "shutdown"); } catch (e) {}
  76.         webSocket = null;
  77.     }
  78.     if (okHttpClient) {
  79.         try { okHttpClient.dispatcher().executorService().shutdownNow(); } catch (e) {}
  80.         okHttpClient = null;
  81.     }
  82. }

  83. // ========== 建立连接(okhttp3 方案) ==========
  84. function connect() {
  85.     // 先清旧资源
  86.     shutdownClient();

  87.     state.connected = false;
  88.     state.err = null;

  89.     // 构造新 OkHttpClient
  90.     okHttpClient = new OkHttpClient.Builder()
  91.         .pingInterval(10, TimeUnit.SECONDS)
  92.         .connectTimeout(config.connectTimeoutSec, TimeUnit.SECONDS)
  93.         .readTimeout(config.readTimeoutSec, TimeUnit.SECONDS)
  94.         .build();

  95.     // 构造 listener
  96.     var listener = new WebSocketListener({
  97.         onOpen: function (wsObj, response) {
  98.             state.connected = true;
  99.             state.err = null;
  100.             state.reconnectCount = 0;
  101.             print.log("WS: onOpen");
  102.             printl("✅ 连接成功(onOpen)");
  103.             startScreenshotLoop();
  104.         },
  105.         onMessage: function (wsObj, message) {
  106.             var raw;
  107.             try { raw = String(message); } catch (e) { raw = ""; }
  108.             print.log("WS: onMessage len=" + raw.length);

  109.             var parsed = parseServerMessage(raw);

  110.             if (parsed.type === "WELCOME") {
  111.                 state.saveDir = parsed.save_dir || "";
  112.                 state.saveUrlPrefix = parsed.save_file_url || "";
  113.                 printl("&#128233; WELCOME 客户端" + parsed.id);
  114.                 if (state.saveDir) {
  115.                     printl("&#128193; 保存目录: " + state.saveDir);
  116.                     printl("&#128279; 目录URL: " + state.saveUrlPrefix);
  117.                 }
  118.             } else if (parsed.type === "IMG_SAVED") {
  119.                 state.totalConfirmed++;
  120.                 printl("&#128190; 服务器已保存图片 " + parsed.seq);
  121.                 printl("    大小: " + parsed.sizeTxt);
  122.                 printl("    路径: " + parsed.absPath);
  123.                 printl("    &#128279; " + parsed.fileUrl);
  124.             } else if (parsed.type === "IMG_FAIL") {
  125.                 printl("&#128308; 服务器保存图片失败: " + parsed.raw);
  126.             } else if (parsed.type === "ECHO") {
  127.                 printl("&#128233; 回显: " + parsed.text.substring(0, 150));
  128.             } else {
  129.                 // 未知格式(旧版服务器返回)
  130.                 printl("&#128233; 收到: " + raw.substring(0, 200) + (raw.length > 200 ? "..." : ""));
  131.             }
  132.         },
  133.         onClosed: function (wsObj, code, reason) {
  134.             state.connected = false;
  135.             state.closeReason = reason || "closed";
  136.             print.log("WS: onClosed code=" + code + " reason=" + reason);
  137.             printl("&#128268; 连接关闭(onClosed code=" + code + ")");
  138.             stopScreenshotLoop();
  139.             scheduleReconnect();
  140.         },
  141.         onFailure: function (wsObj, throwable, response) {
  142.             state.connected = false;
  143.             state.err = (throwable ? String(throwable.getMessage()) : "unknown_failure");
  144.             print.log("WS: onFailure " + state.err);
  145.             printl("❌ 连接错误(onFailure): " + state.err);
  146.             stopScreenshotLoop();
  147.             scheduleReconnect();
  148.         }
  149.     });

  150.     // 发起连接
  151.     var url = "ws://" + config.serverUrl;
  152.     printl("正在连接: " + url + "(" + config.connectTimeoutSec + " 秒超时)");

  153.     try {
  154.         var request = new Request.Builder().url(url).build();
  155.         webSocket = okHttpClient.newWebSocket(request, listener);
  156.     } catch (e) {
  157.         state.err = String(e.message);
  158.         printl("❌ newWebSocket 抛异常: " + state.err);
  159.         scheduleReconnect();
  160.     }

  161.     // 同步等最多 connectTimeoutSec + 5 秒看事件
  162.     var waited = 0;
  163.     while (!state.connected && !state.err && waited < (config.connectTimeoutSec + 5) * 1000) {
  164.         sleep.millisecond(100);
  165.         waited += 100;
  166.     }
  167.     if (!state.connected && !state.err) {
  168.         state.err = "连接超时(" + (config.connectTimeoutSec + 5) + " 秒内无 onOpen/onFailure)";
  169.         printl("❌ " + state.err);
  170.         scheduleReconnect();
  171.     }
  172. }

  173. // ========== 重连调度 ==========
  174. function scheduleReconnect() {
  175.     if (state.reconnectCount >= config.maxReconnectAttempts) {
  176.         printl("&#128721; 已达到最大重连次数 " + config.maxReconnectAttempts + ",停止");
  177.         return;
  178.     }
  179.     state.reconnectCount++;
  180.     printl("⏱️  重连 " + state.reconnectCount + "/" + config.maxReconnectAttempts + "," + (config.reconnectInterval / 1000).toFixed(1) + " 秒后...");

  181.     shutdownClient();

  182.     setTimeout(function () {
  183.         connect();
  184.     }, config.reconnectInterval);
  185. }

  186. // ========== 截一张图并发送 ==========
  187. function sendOne() {
  188.     if (!state.connected || !webSocket) {
  189.         print.log("跳过截图:未连接");
  190.         return;
  191.     }
  192.     try {
  193.         print.log("截取屏幕...");
  194.         printl("&#128248; 截图中...");

  195.         var bitmap = screen.screenShotFull();
  196.         if (!bitmap) { printl("❌ 截图失败(返回 null)"); return; }

  197.         print.log("转 Base64...");
  198.         var base64 = "" + bitmap.toBase64();   // Java ByteString → JS 字符串,必须用 ""+

  199.         if (!base64) { printl("❌ Base64 为空"); return; }

  200.         var chars = base64.length;
  201.         var estKB = Math.round(chars * 0.75 / 1024);
  202.         printl("&#128230; 图片大小: " + chars + " 字符(约 " + estKB + " KB)");

  203.         try { bitmap.recycle(); } catch (e) {}

  204.         state.totalSent++;
  205.         printl("&#128228; 发送图片 #" + state.totalSent + " ...");
  206.         webSocket.send(base64);

  207.         printl("✅ 图片 #" + state.totalSent + " 已投递(" + estKB + " KB)");

  208.     } catch (e) {
  209.         printl("❌ sendOne 异常: " + e.message);
  210.         print.log("sendOne: " + e.message);
  211.     }
  212. }

  213. // ========== 定时截图循环 ==========
  214. function startScreenshotLoop() {
  215.     if (timer) { try { clearInterval(timer); } catch (e) {} timer = null; }

  216.     print.log("定时截图循环启动, 间隔 " + config.screenshotInterval + "ms");
  217.     printl("⏰ 定时截图已启动(间隔 " + (config.screenshotInterval / 1000) + " 秒)");

  218.     // 首张立即来
  219.     setTimeout(function () { sendOne(); }, 300);

  220.     timer = setInterval(function () {
  221.         if (state.connected && webSocket) sendOne();
  222.     }, config.screenshotInterval);
  223. }

  224. function stopScreenshotLoop() {
  225.     if (timer) {
  226.         try { clearInterval(timer); } catch (e) {}
  227.         timer = null;
  228.         print.log("停止定时截图循环");
  229.     }
  230. }

  231. // ========== 关闭清理 ==========
  232. function cleanup() {
  233.     stopScreenshotLoop();
  234.     shutdownClient();
  235.     state.connected = false;
  236.     printl("&#128268; 资源已清理");
  237. }

  238. // ========== 主程序 ==========
  239. function main() {
  240.     try {
  241.         printl("========================================");
  242.         printl("  WebSocket 屏幕截图传输 - okhttp3 版");
  243.         printl("  服务器: " + config.serverUrl);
  244.         printl("  截图间隔: " + (config.screenshotInterval / 1000) + " 秒");
  245.         printl("  总运行: " + (config.runDuration / 1000) + " 秒");
  246.         printl("  最大重连: " + config.maxReconnectAttempts + " 次");
  247.         printl("========================================");
  248.         printl("ℹ️ 请确认 PC 已运行: python WebSocket测试服务器.py");

  249.         connect();

  250.         print.log("倒计时 " + (config.runDuration / 1000) + " 秒...");
  251.         printl("⏳ 运行 " + (config.runDuration / 1000) + " 秒后自动结束");
  252.         sleep.millisecond(config.runDuration);

  253.         cleanup();

  254.         printl("");
  255.         printl("===== 执行结束 =====");
  256.         printl("  尝试发送: " + state.totalSent + " 张");
  257.         printl("  服务器确认: " + state.totalConfirmed + " 张");
  258.         if (state.saveDir) printl("  PC 保存目录: " + state.saveDir);
  259.         print.log("===== 屏幕截图传输结束, 发送 " + state.totalSent + " 张 =====");

  260.     } catch (e) {
  261.         print.log("主程序异常: " + e.message);
  262.         printl("❌ 程序错误: " + e.message);
  263.         try { cleanup(); } catch (e2) {}
  264.     }
  265. }

  266. main();
复制代码







欢迎光临 B2B网络软件 (http://bbs.niubt.cn/) Powered by Discuz! X3.2