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

后续

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

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


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

相关推荐
用户00447295382537 分钟前
练歌镜:让眼镜听懂“循环这一句”
javascript
yuyuxun13 小时前
协同过滤的校园二手物品智能推荐系统的设计与实现 毕业设计-附源码40082
javascript·vue.js·spring boot·python·数据分析·django·课程设计
总要学点什么7 小时前
第105篇:三维特效-流动图片墙体效果——让箭头沿墙长滚,它俩竟是同一份代码
开发语言·javascript·ecmascript·gis·webgl·材质·cesium
Agent世界8 小时前
用 CDP 做发布自动化:四道机器闸门与产物验收
前端·javascript
总要学点什么8 小时前
第104篇:三维特效-流动墙体效果——让贴图沿墙流动,它却只肯走一条对角线
开发语言·javascript·ecmascript·gis·webgl·材质·cesium
程序员大阳8 小时前
副队长ES6+教程(3)--解构赋值
前端·javascript·es6·赋值·解构
神膘护体小月半9 小时前
css - 元素背景图由 hover 触发,初次加载时闪动的解决办法
前端·javascript·css
程序员大阳9 小时前
副队长ES6+教程(2)--let 与 const
前端·javascript·es6·const·let·var
曦樂~10 小时前
【Web Development】03JavaScript 基础和事件
开发语言·前端·javascript
码云社区11 小时前
智慧物业系统选型指南:房屋档案、账单管理与报修协作
前端·javascript·vue.js·智慧物业