import debug from "debug" import net from 'node:net'; const log = { app: debug('ip_monitor') }; // IP 监控配置接口 interface IPMonitorConfig { timeout?: number; // 超时时间(毫秒) retries?: number; // 重试次数 interval?: number; // 监控间隔(毫秒) } // IP 监控结果接口 export interface IPMonitorResult { success: boolean; // 是否成功 responseTime?: number; // 响应时间(毫秒) packetLoss?: number; // 丢包率(百分比) error?: string; // 错误信息 } // 默认配置 const DEFAULT_CONFIG: IPMonitorConfig = { timeout: 1000, retries: 3, interval: 60000 }; // IP 监控类 export class IPMonitor { private config: IPMonitorConfig; private monitoring: Map = new Map(); constructor(config: IPMonitorConfig = {}) { this.config = { ...DEFAULT_CONFIG, ...config }; } // 开始监控指定 IP async startMonitor(ip: string, callback: (result: IPMonitorResult) => void) { if (this.monitoring.has(ip)) { log.app(`IP ${ip} 已经在监控中`); return; } const monitor = async () => { try { const result = await this.ping(ip); callback(result); } catch (error) { log.app(`监控 IP ${ip} 时发生错误:`, error); callback({ success: false, error: error instanceof Error ? error.message : '未知错误' }); } }; // 立即执行一次 await monitor(); // 设置定时监控 const interval = setInterval(monitor, this.config.interval); this.monitoring.set(ip, interval); log.app(`开始监控 IP: ${ip}`); } // 停止监控指定 IP stopMonitor(ip: string) { const interval = this.monitoring.get(ip); if (interval) { clearInterval(interval); this.monitoring.delete(ip); log.app(`停止监控 IP: ${ip}`); } } // 停止所有监控 stopAll() { for (const [ip, interval] of this.monitoring) { clearInterval(interval); this.monitoring.delete(ip); } log.app('已停止所有 IP 监控'); } // 执行 ping 操作 private async ping(ip: string): Promise { const results: number[] = []; let successCount = 0; let totalTime = 0; for (let i = 0; i < this.config.retries!; i++) { try { const startTime = Date.now(); const result = await this.tcpPing(ip); const endTime = Date.now(); if (result) { const responseTime = endTime - startTime; results.push(responseTime); totalTime += responseTime; successCount++; } } catch (error) { log.app(`Ping 尝试 ${i + 1} 失败:`, error); } } // 计算平均响应时间和丢包率 const avgResponseTime = successCount > 0 ? totalTime / successCount : undefined; const packetLoss = ((this.config.retries! - successCount) / this.config.retries!) * 100; return { success: successCount > 0, responseTime: avgResponseTime, packetLoss: packetLoss }; } // TCP ping 实现 private async tcpPing(ip: string): Promise { return new Promise((resolve, reject) => { const socket = new net.Socket(); let timeout = false; // 设置超时 const timer = setTimeout(() => { timeout = true; socket.destroy(); reject(new Error('连接超时')); }, this.config.timeout); socket.on('connect', () => { clearTimeout(timer); socket.destroy(); resolve(true); }); socket.on('error', (error) => { clearTimeout(timer); if (!timeout) { reject(error); } }); // 尝试连接 socket.connect(80, ip); }); } } // 导出单例实例 export const ipMonitor = new IPMonitor();