「桌面端」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) => {
   ... //监听并处理
})

后续

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

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


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

相关推荐
一路向前的月光4 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   4 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web4 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
Jiaberrr5 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
安冬的码畜日常7 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
太阳花ˉ7 小时前
html+css+js实现step进度条效果
javascript·css·html
john_hjy8 小时前
11. 异步编程
运维·服务器·javascript
风清扬_jd8 小时前
Chromium 中JavaScript Fetch API接口c++代码实现(二)
javascript·c++·chrome
yanlele8 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范