likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 17

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

背景

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

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

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

分析

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

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

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

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

方案

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

实现

子进程执行

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变更来监听网络变化,减少通信成本。

主进程监控

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',
        );
    }
}

任意页面监听事件

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

后续

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

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


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

「桌面端」Electron 实时网络环境监控
转载自:https://juejin.cn/post/7266670997735227449
评论
请登录