Files
EveryPublish/tools/diag-connection.mjs
T

56 lines
2.5 KiB
JavaScript

#!/usr/bin/env node
// 连接诊断: TCP / WS 分段计时, 零依赖, Node >= 22 (内置 WebSocket)
// 用法: node tools/diag-connection.mjs ws://192.168.1.5:3001 [次数]
// 说明: WS 模式下服务端需对 {"type":"ping"} 回应任意消息(建议 {"type":"pong"})
import net from "node:net";
const url = process.argv[2];
const times = Number(process.argv[3] || 5);
if (!url) {
console.error("用法: node tools/diag-connection.mjs <ws://host:port | http://host:port> [次数]");
process.exit(1);
}
const u = new URL(url);
const host = u.hostname;
const port = Number(u.port || (u.protocol === "wss:" || u.protocol === "https:" ? 443 : 80));
const isWs = u.protocol === "ws:" || u.protocol === "wss:";
const tcpMs = [], openMs = [], rttMs = [];
for (let i = 0; i < times; i++) {
const t0 = performance.now();
try {
await new Promise((res, rej) => {
const s = net.connect({ host, port });
const to = setTimeout(() => { s.destroy(); rej(new Error("TCP timeout")); }, 3000);
s.once("connect", () => { clearTimeout(to); tcpMs.push(performance.now() - t0); s.destroy(); res(); });
s.once("error", (e) => { clearTimeout(to); rej(e); });
});
} catch (err) { tcpMs.push(-1); console.warn("第" + (i+1) + "次 TCP 失败: " + err.message); }
if (!isWs) continue;
const t1 = performance.now();
try {
const ws = new WebSocket(url);
await new Promise((res, rej) => { ws.onopen = res; ws.onerror = () => rej(new Error("WS open 失败")); });
openMs.push(performance.now() - t1);
const t2 = performance.now();
ws.send(JSON.stringify({ type: "ping", t: Date.now() }));
await new Promise((res) => {
const to = setTimeout(() => { rttMs.push(-1); res(); }, 3000);
ws.onmessage = () => { clearTimeout(to); rttMs.push(performance.now() - t2); res(); };
});
ws.close();
} catch (err) { openMs.push(-1); console.warn("第" + (i+1) + "次 WS 失败: " + err.message); }
}
const stat = (a) => {
const v = a.filter((x) => x >= 0);
if (!v.length) return "全部失败";
const avg = v.reduce((s, x) => s + x, 0) / v.length;
return "avg=" + avg.toFixed(1) + "ms min=" + Math.min(...v).toFixed(1) + "ms max=" + Math.max(...v).toFixed(1) + "ms";
};
console.log("目标: " + url + " (" + host + ":" + port + ") x" + times);
console.log("TCP连接 : " + stat(tcpMs) + " <- >20ms 查防火墙/IPv6/代理");
if (isWs) {
console.log("WS握手 : " + stat(openMs) + " <- >50ms 查服务端WS框架/鉴权");
console.log("消息RTT : " + stat(rttMs) + " <- >50ms 查串行往返/服务端处理");
}