「桌面端」Electron 实时网络环境监控

笔者看了很多文章,都有提到需要自建网络监控,但没有开源具体的实现方式,笔者在此摸索了一下,仅供大家参考。

背景

Electron 官方虽然有提供网络在线/离线探测方案,但这个方案是基于浏览器本身的。使用浏览器标准 APInavigator.onLine来判断网络环境 Electron online-offline-events。

这个方式虽然是 W3C 标准的,但在多篇文章中,都提到这个方式在线/离线情况是不准确的,它是基于本地网络判断,就是在局域网下也是会返回有网,不能说明网络环境是在线的情况。

如何实时获取可靠的网络环境,对于桌面端用户体验来说也是至关重要的。

分析

笔者确实没有找到现成的方案可以采用,从语雀桌面端技术架构实践中也只是提到他们使用了系统级的网络监测方案,但没有说是基于什么技术来做的。笔者猜测可能会底层一些,比如链接 C 库来实现。但笔者公司桌面端项目还没有成熟,贸然引入多技术栈,会带来额外的负担和成本。

那从需要的结果倒推,我们需要:

  • 具有网络实时检测能力。
  • 可以判断是能连到广域网络环境的。
  • 最好是系统级的方法。

那在这个基础上,笔者想了几种方案:

  • 可以用electron-edge-js来调用 .Net 本地服务,这个包现在也是在项目中使用的,所以不会增大应用体积。但它只对 Windows 生效,Mac 需要安装 .Net Core,对于我们项目来说不合适。
  • Electron 提供了net.resolveHost 方法,可以解析当前域名,但我们当前 Electron 版本没有这个 API 可用。
  • 项目中可以使用shelljs,那我们定时启动终端去ping域名是否可行?可以是可以,但也可以不引用shelljs来实现。

方案

  • 使用单独子进程监听(不增加主进程)。
  • 使用 node 的 DNS 模块 dns 我们主站域名,如果拿得到 IP,可认为网络环境正常。
  • 每秒执行一次上次操作,缓存至内存,提供广播事件给监听者。
  • 主进程广播事件,渲染进程监听事件。

实现

子进程执行

javascript 复制代码
const dns = require('dns');
const process = require('process');

const options = {
    family: 4,
    servers: ['8.8.8.8', '114.114.114.114'],
};

const host = 'www.gaoding.com';

let networkStatus = true;

setInterval(() => {
    dns.lookup(host, options, (err, _) => {
        if (err) {
            console.error(`[network-monitor] error: ${err.message}`);
        }
        emitNetworkStatusDidChange(err ? false : true);
    });
}, 1000);

function emitNetworkStatusDidChange(status) {
    if (networkStatus === status) {
        return;
    }
    networkStatus = status;
    process.send({
        type: 'network_status',
        content: status,
    });
}
  • 通过 DNS 轮询主站域名,来判断是否有网络。
  • 通过process发送消息给主进程处理。
  • 通过networkStatus变更来监听网络变化,减少通信成本。

主进程监控

typescript 复制代码
import Module from 'module';
import { ChildProcess, fork } from 'child_process';

/**
 * 网络环境监听管理
 */
export class GDNetWatchManager {
    ...

    private isOnline: boolean = true;
    private child?: ChildProcess;

    /**
     * 启动监听管理
     */
    public start() {
        const path = Module._resolveFilename('@gaoding/network-monitor', module, true);

        const child = fork(path);

        child.on('message', (data: any) => {
            if (data.type === 'network_status') {
                !data.content && console.error(`网络连接异常`);
                this.changeStatus(data.content);
            }
        });
        this.child = child;
    }
    ...
    
    // ================== Private Methods ================ //
    private changeStatus(online: boolean) {
        if (this.isOnline === online) {
            return;
        }
        this.isOnline = online;
        GNBManager.shared.network.emitNetworkStatusDidChangeEvent(
            online,
            online ? 'unknown' : 'none',
        );
    }
}
  • child_process.fork来构建具有 node 环境的子进程,Electron 版本支持的话,也可以选择 utility-process
  • 通过child_process.on来监听消息变化。
  • GNBManager.shared.network.emitNetworkStatusDidChangeEvent是发送事件广播,这里用了跨端工具链的实现(具体桌面端如何实现待作者后续文章补充)

任意页面监听事件

typescript 复制代码
GNB.event.network.onNetworkStatusDidChangeEvent((online, type) => {
   ... //监听并处理
})

后续

一个网络监听就开一个子进程是很浪费,所以后续会归并到守护进程中来增强整体性能。

本文只是桌面端开发过程中遇到的很小的一点,希望能抛砖引玉。


感谢阅读,如果对你有用请点个赞 ❤️

相关推荐
福兮说7 小时前
设计稿是 #4A7C6F,页面量出来是 #4B7C6F:HEX、HSL、透明度、canvas 来回转的七个坑
前端·javascript·css·canvas
凤城老人8 小时前
从 PyQt6 到 Electron:给 Edge TTS 做一个“多角色配音机“的踩坑手记
javascript·typescript·electron
Dovis(誓平步青云)8 小时前
浇水提醒刚弹出又消失,植物状态别只存一个百分比
开发语言·前端·javascript·pdf·ecmascript·电脑
码艺-Alimjan9 小时前
Vben Admin 新增维吾尔语 Vben-Modal的关键坑之一
前端·javascript·vue.js
可乐鸡翅yeah_9 小时前
hls.js 手动自定义 http 请求 loader,修改请求头实战
开发语言·前端·javascript·网络协议·http·ecmascript·m3u8在线
yivifu10 小时前
中文古籍电子书注释集成
前端·javascript·python·beautifulsoup·epub
weixin_4482902511 小时前
书庐开发实战教学
javascript·css·html
默_笙11 小时前
🛴 从散件到整机:DeepAgents 与 Agent 身上预留的那些"插槽"(前置介绍)
前端·javascript
一木 之林11 小时前
DeepSeek Agent 开发(一)
开发语言·前端·javascript
樱花落木兰13 小时前
分布式登录实战:Session 会话共享改造,Redis 存储用户登录状态
java·javascript·数据库·redis·分布式·缓存