Electron 实战:构建跨平台网络性能监控工具(含 TCP/UDP 检测、延迟测试、数据可视化)
智慧医疗服务平台作为鸿蒙 + Electron 技术融合的核心民生场景应用,其核心价值在于通过分布式技术打破医疗行业的 “设备孤岛” 与 “数据孤岛”,通过跨端协同提升诊疗效率与医疗资源利用率,通过安全合规保障患者隐私与诊疗安全,最终实现 “高效、安全、普惠” 的医疗服务目标。本文从医疗行业痛点、技术选型、架构设计、核心场景落地、挑战解决到未来演进,全面阐述了平台开发的全流程逻辑,强调了 “端 -
·
Electron 基于 Chromium 和 Node.js,既能利用前端技术栈实现美观的 UI,又能通过 Node.js 调用系统底层网络 API。本文以网络性能监控工具为场景,开发一款支持 TCP 端口检测、UDP 连通性测试、网络延迟实时监控的桌面应用,覆盖 Electron 核心能力:主进程异步任务处理、渲染进程数据可视化、跨平台网络 API 调用、系统通知集成。
一、环境准备
1. 初始化项目
mkdir electron-network-monitor
cd electron-network-monitor
npm init -y
# 安装核心依赖
npm install electron@28.0.0 --save-dev
npm install ping.js net socket.io-client chart.js --save
2. 配置 package.json
{
"name": "network-monitor",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"package": "electron-packager . NetworkMonitor --platform=win32,darwin,linux --arch=x64 --out=dist"
},
"devDependencies": {
"electron": "^28.0.0",
"electron-packager": "^17.1.2"
},
"dependencies": {
"chart.js": "^4.4.8",
"net": "^1.0.2",
"ping.js": "^0.3.0",
"socket.io-client": "^4.7.5"
}
}
二、核心代码实现
1. 主进程(main.js)
负责网络检测、系统通知、窗口管理,通过 IPC 与渲染进程通信:
const { app, BrowserWindow, ipcMain, Notification, dialog } = require('electron');
const path = require('path');
const net = require('net');
const Ping = require('ping.js');
const dgram = require('dgram');
let mainWindow;
const ping = new Ping();
// 创建主窗口
function createWindow() {
mainWindow = new BrowserWindow({
width: 1000,
height: 700,
minWidth: 800,
minHeight: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true
},
title: 'Electron 网络性能监控工具'
});
mainWindow.loadFile('index.html');
// 开发阶段打开开发者工具
// mainWindow.webContents.openDevTools();
mainWindow.on('closed', () => {
mainWindow = null;
});
}
// TCP 端口检测
function checkTcpPort(host, port, timeout = 3000) {
return new Promise((resolve) => {
const socket = new net.Socket();
const timer = setTimeout(() => {
socket.destroy();
resolve({ status: 'closed', host, port, time: timeout });
}, timeout);
socket.connect(port, host, () => {
clearTimeout(timer);
socket.destroy();
resolve({ status: 'open', host, port, time: Date.now() - timer._idleStart });
});
socket.on('error', () => {
clearTimeout(timer);
resolve({ status: 'error', host, port, time: timeout });
});
});
}
// UDP 连通性测试
function checkUdpPort(host, port, timeout = 3000) {
return new Promise((resolve) => {
const client = dgram.createSocket('udp4');
const message = Buffer.from('network-monitor-test');
const timer = setTimeout(() => {
client.close();
resolve({ status: 'timeout', host, port, time: timeout });
}, timeout);
client.send(message, 0, message.length, port, host, (err) => {
if (err) {
clearTimeout(timer);
client.close();
resolve({ status: 'error', host, port, time: timeout });
}
});
client.on('message', () => {
clearTimeout(timer);
client.close();
resolve({ status: 'open', host, port, time: Date.now() - timer._idleStart });
});
});
}
// 网络延迟测试(Ping)
function testPing(host, count = 5) {
return new Promise((resolve) => {
const results = [];
let completed = 0;
for (let i = 0; i < count; i++) {
ping.ping(host, (err, data) => {
completed++;
if (err) {
results.push({ status: 'fail', time: null });
} else {
results.push({ status: 'success', time: data.time });
}
if (completed === count) {
const avgTime = results
.filter(r => r.status === 'success')
.reduce((sum, r) => sum + r.time, 0) / Math.max(1, results.filter(r => r.status === 'success').length);
resolve({
host,
count,
results,
avgTime: isNaN(avgTime) ? 0 : avgTime.toFixed(2)
});
}
});
}
});
}
// 显示系统通知
function showNotification(title, body) {
if (Notification.isSupported()) {
new Notification({ title, body, silent: false }).show();
} else {
dialog.showMessageBox(mainWindow, { type: 'info', title, message: body });
}
}
// 注册 IPC 事件
function registerIpcHandlers() {
// TCP 端口检测请求
ipcMain.on('network:check-tcp', async (event, { host, port, timeout }) => {
const result = await checkTcpPort(host, port, timeout);
event.reply('network:tcp-result', result);
if (result.status === 'closed') {
showNotification('TCP 端口检测', `${host}:${port} 端口关闭`);
}
});
// UDP 端口检测请求
ipcMain.on('network:check-udp', async (event, { host, port, timeout }) => {
const result = await checkUdpPort(host, port, timeout);
event.reply('network:udp-result', result);
});
// Ping 延迟测试请求
ipcMain.on('network:test-ping', async (event, { host, count }) => {
const result = await testPing(host, count);
event.reply('network:ping-result', result);
if (result.avgTime > 100) {
showNotification('网络延迟警告', `${host} 平均延迟 ${result.avgTime}ms,网络状况不佳`);
}
});
}
// 应用生命周期管理
app.whenReady().then(() => {
createWindow();
registerIpcHandlers();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
2. 渲染进程(index.html)
负责 UI 交互、数据可视化、用户输入处理:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>网络性能监控工具</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; padding: 20px; background-color: #f5f5f5; }
.container { max-width: 1000px; margin: 0 auto; }
.tab-container { display: flex; margin-bottom: 20px; border-bottom: 1px solid #ddd; }
.tab-btn { padding: 10px 20px; border: none; background: transparent; cursor: pointer; font-size: 16px; }
.tab-btn.active { border-bottom: 2px solid #2196F3; color: #2196F3; }
.tab-content { display: none; padding: 20px; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.tab-content.active { display: block; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; font-weight: bold; }
input { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
.btn { padding: 10px 20px; background: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; }
.btn:hover { background: #1976D2; }
.result { margin-top: 20px; padding: 15px; background: #f8f8f8; border-radius: 4px; white-space: pre-wrap; }
canvas { width: 100%; height: 300px; margin-top: 20px; }
</style>
</head>
<body>
<div class="container">
<h1>Electron 网络性能监控工具</h1>
<div class="tab-container">
<button class="tab-btn active" onclick="switchTab('tcp')">TCP 端口检测</button>
<button class="tab-btn" onclick="switchTab('udp')">UDP 端口检测</button>
<button class="tab-btn" onclick="switchTab('ping')">网络延迟测试</button>
</div>
<!-- TCP 检测标签页 -->
<div id="tcp" class="tab-content active">
<div class="form-group">
<label>目标主机</label>
<input type="text" id="tcpHost" placeholder="例如:127.0.0.1 或 www.baidu.com" value="www.baidu.com">
</div>
<div class="form-group">
<label>目标端口</label>
<input type="number" id="tcpPort" placeholder="例如:80、443" value="80">
</div>
<div class="form-group">
<label>超时时间(ms)</label>
<input type="number" id="tcpTimeout" value="3000">
</div>
<button class="btn" onclick="checkTcp()">开始检测</button>
<div id="tcpResult" class="result"></div>
</div>
<!-- UDP 检测标签页 -->
<div id="udp" class="tab-content">
<div class="form-group">
<label>目标主机</label>
<input type="text" id="udpHost" placeholder="例如:127.0.0.1" value="127.0.0.1">
</div>
<div class="form-group">
<label>目标端口</label>
<input type="number" id="udpPort" placeholder="例如:8080" value="8080">
</div>
<div class="form-group">
<label>超时时间(ms)</label>
<input type="number" id="udpTimeout" value="3000">
</div>
<button class="btn" onclick="checkUdp()">开始检测</button>
<div id="udpResult" class="result"></div>
</div>
<!-- Ping 延迟测试标签页 -->
<div id="ping" class="tab-content">
<div class="form-group">
<label>目标主机</label>
<input type="text" id="pingHost" placeholder="例如:www.baidu.com" value="www.baidu.com">
</div>
<div class="form-group">
<label>测试次数</label>
<input type="number" id="pingCount" value="5" min="1" max="10">
</div>
<button class="btn" onclick="testPing()">开始测试</button>
<div id="pingResult" class="result"></div>
<canvas id="pingChart"></canvas>
</div>
</div>
<script>
const { ipcRenderer } = require('electron');
const Chart = require('chart.js');
let pingChart = null;
// 切换标签页
function switchTab(tabId) {
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
document.querySelector(`.tab-btn[onclick="switchTab('${tabId}')"]`).classList.add('active');
document.getElementById(tabId).classList.add('active');
}
// TCP 端口检测
function checkTcp() {
const host = document.getElementById('tcpHost').value;
const port = parseInt(document.getElementById('tcpPort').value);
const timeout = parseInt(document.getElementById('tcpTimeout').value);
const resultEl = document.getElementById('tcpResult');
resultEl.textContent = '检测中...';
ipcRenderer.send('network:check-tcp', { host, port, timeout });
ipcRenderer.once('network:tcp-result', (event, result) => {
resultEl.textContent = JSON.stringify(result, null, 2);
});
}
// UDP 端口检测
function checkUdp() {
const host = document.getElementById('udpHost').value;
const port = parseInt(document.getElementById('udpPort').value);
const timeout = parseInt(document.getElementById('udpTimeout').value);
const resultEl = document.getElementById('udpResult');
resultEl.textContent = '检测中...';
ipcRenderer.send('network:check-udp', { host, port, timeout });
ipcRenderer.once('network:udp-result', (event, result) => {
resultEl.textContent = JSON.stringify(result, null, 2);
});
}
// Ping 延迟测试
function testPing() {
const host = document.getElementById('pingHost').value;
const count = parseInt(document.getElementById('pingCount').value);
const resultEl = document.getElementById('pingResult');
resultEl.textContent = '测试中...';
ipcRenderer.send('network:test-ping', { host, count });
ipcRenderer.once('network:ping-result', (event, result) => {
resultEl.textContent = JSON.stringify(result, null, 2);
renderPingChart(result.results);
});
}
// 渲染 Ping 延迟图表
function renderPingChart(results) {
const ctx = document.getElementById('pingChart').getContext('2d');
const labels = results.map((_, index) => `第 ${index+1} 次`);
const data = results.map(r => r.time || 0);
if (pingChart) pingChart.destroy();
pingChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: '延迟 (ms)',
data: data,
borderColor: '#2196F3',
backgroundColor: 'rgba(33, 150, 243, 0.1)',
borderWidth: 2,
tension: 0.3,
fill: true
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true,
title: { display: true, text: '延迟 (ms)' }
}
}
}
});
}
</script>
</body>
</html>
三、核心功能解析
1. 网络检测核心实现
- TCP 端口检测:利用 Node.js
net模块创建 Socket 连接,通过超时机制判断端口状态(开启 / 关闭 / 异常); - UDP 连通性测试:通过
dgram模块发送测试数据包,监听是否收到响应来判断端口可用性; - Ping 延迟测试:基于
ping.js库实现多轮 ICMP 测试,计算平均延迟,支持自定义测试次数。
2. 主进程与渲染进程通信
- 异步任务处理:网络检测属于耗时操作,全部放在主进程执行,避免阻塞渲染进程的 UI 渲染;
- IPC 双向通信:
- 渲染进程通过
ipcRenderer.send发送检测请求; - 主进程通过
event.reply返回检测结果; - 使用
once监听结果,防止重复绑定事件。
- 渲染进程通过
3. 数据可视化与用户交互
- Chart.js 图表渲染:将 Ping 测试的每轮延迟数据绘制成折线图,直观展示网络波动情况;
- 标签页切换:通过原生 JS 实现标签页功能,分类展示不同检测模块;
- 实时状态反馈:检测过程中显示「检测中...」,完成后展示格式化的 JSON 结果。
4. 系统通知集成
- 跨平台通知:利用 Electron
Notification模块实现系统级通知,TCP 端口关闭或网络延迟过高时自动推送警告; - 降级处理:若系统不支持通知,则通过
dialog.showMessageBox弹出提示框。
四、运行与打包
1. 启动应用
npm start
启动后可进行三项操作:
- TCP 端口检测:输入主机和端口,检测目标端口是否开放(默认检测百度 80 端口);
- UDP 端口检测:测试 UDP 端口连通性(默认检测本地 8080 端口);
- 网络延迟测试:对目标主机执行多轮 Ping 测试,生成延迟报告和折线图。
2. 打包应用
# 安装打包工具
npm install electron-packager --save-dev
# 打包全平台
npm run package
# 打包指定平台
electron-packager . NetworkMonitor --platform=win32 --arch=x64 --out=dist
五、进阶优化方向
1. 功能扩展
- 批量检测:支持导入 IP 端口列表,批量执行检测并生成报告;
- 持续监控:添加定时任务,周期性检测网络状态,记录历史数据;
- 路由追踪:集成
traceroute功能,显示数据包传输路径; - 带宽测试:通过上传下载测试文件,计算网络带宽。
2. 性能优化
- 连接池复用:TCP 检测时复用 Socket 连接,减少重复创建连接的开销;
- 结果缓存:缓存近期检测结果,避免重复检测相同主机;
- 进度条展示:为批量检测添加进度条,提升用户体验。
3. 安全与兼容性
- 输入验证:严格校验用户输入的主机和端口,防止恶意输入;
- 权限适配:Linux 平台下 Ping 可能需要 root 权限,添加权限检测和提示;
- 跨平台兼容:处理不同系统的网络 API 差异,例如 Windows 的 ICMP 限制。
六、总结
本文以网络性能监控为场景,展示了 Electron 开发跨平台桌面应用的完整流程,核心亮点包括:
- Node.js 网络 API 调用:直接使用
netdgram模块实现底层网络操作; - 主渲染进程分工:耗时任务主进程处理,UI 渲染渲染进程负责,保证应用流畅性;
- 数据可视化:结合 Chart.js 实现检测结果的图表化展示;
- 系统级能力集成:利用 Electron 原生 API 实现通知推送、对话框等功能。
该工具可作为网络运维人员的辅助工具,也可作为 Electron 网络开发的入门案例,扩展后可应用于企业内网监控、服务器状态巡检等场景。
更多推荐




所有评论(0)