You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下无需轮询获取NetworkManager连接状态变更通知的Go实现方案

监听Linux NetworkManager网络连接状态变更的Go实现方案

要替代定时轮询,你可以利用Linux下的DBus事件机制(NetworkManager官方推荐方式),或者通过inotify监听NetworkManager状态文件实现事件驱动触发,以下是具体方案:

方案一:通过DBus监听NetworkManager信号

NetworkManager通过系统DBus总线发布状态变更信号,这是最可靠、信息最丰富的事件驱动方式,类似inotify的工作模式。

实现步骤

  1. 安装Go的DBus客户端库:
go get github.com/godbus/dbus/v5
  1. 示例代码(监听全局网络状态变更):
package main

import (
	"fmt"
	"os"

	"github.com/godbus/dbus/v5"
)

func main() {
	// 连接系统DBus总线
	conn, err := dbus.SystemBus()
	if err != nil {
		fmt.Fprintln(os.Stderr, "无法连接系统DBus:", err)
		os.Exit(1)
	}
	defer conn.Close()

	// 订阅NetworkManager的StateChanged信号
	matchRule := "type='signal',interface='org.freedesktop.NetworkManager',member='StateChanged'"
	if call := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, matchRule); call.Err != nil {
		fmt.Fprintln(os.Stderr, "添加信号匹配失败:", call.Err)
		os.Exit(1)
	}

	// 接收信号的通道
	sigChan := make(chan *dbus.Signal, 10)
	conn.Signal(sigChan)

	fmt.Println("正在监听网络状态变更...")
	for sig := range sigChan {
		if sig.Name == "org.freedesktop.NetworkManager.StateChanged" {
			newState := sig.Body[0].(uint32)
			stateDesc := parseNMState(newState)
			fmt.Printf("网络状态更新: %s (状态码: %d)\n", stateDesc, newState)
			// 在这里触发你的耗时函数
			// yourHeavyFunction()
		}
	}
}

// 解析NetworkManager状态码为可读描述
func parseNMState(state uint32) string {
	switch state {
	case 0:
		return "NM_STATE_UNKNOWN"
	case 10:
		return "NM_STATE_ASLEEP"
	case 20:
		return "NM_STATE_DISCONNECTED"
	case 30:
		return "NM_STATE_DISCONNECTING"
	case 40:
		return "NM_STATE_CONNECTING"
	case 50:
		return "NM_STATE_CONNECTED_LOCAL"
	case 60:
		return "NM_STATE_CONNECTED_SITE"
	case 70:
		return "NM_STATE_CONNECTED_GLOBAL"
	default:
		return "未知状态"
	}
}

若需监听具体连接的激活/停用事件,可修改匹配规则和信号逻辑,订阅org.freedesktop.NetworkManager.ConnectionActivated或org.freedesktop.NetworkManager.ConnectionDeactivated信号,这类信号会携带具体连接的详细信息。

方案二:用inotify监听NetworkManager状态文件

如果偏好轻量实现,可监听NetworkManager的状态文件/run/NetworkManager/state,网络状态变化时该文件内容会同步更新。

实现步骤

  1. 安装Go的inotify库:
go get github.com/fsnotify/fsnotify
  1. 示例代码:
package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/fsnotify/fsnotify"
)

func main() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		fmt.Fprintln(os.Stderr, "创建inotify监听器失败:", err)
		os.Exit(1)
	}
	defer watcher.Close()

	stateFilePath := "/run/NetworkManager/state"
	if err := watcher.Add(stateFilePath); err != nil {
		fmt.Fprintln(os.Stderr, "无法监听状态文件:", err)
		os.Exit(1)
	}

	fmt.Println("正在监听网络状态文件变更...")
	for {
		select {
		case event, ok := <-watcher.Events:
			if !ok {
				return
			}
			// 文件写入或重新创建时触发
			if event.Has(fsnotify.Write) || event.Has(fsnotify.Remove) {
				content, err := os.ReadFile(stateFilePath)
				if err != nil {
					fmt.Fprintln(os.Stderr, "读取状态文件失败:", err)
					continue
				}
				for _, line := range strings.Split(string(content), "\n") {
					if strings.HasPrefix(line, "STATE=") {
						stateStr := strings.TrimPrefix(line, "STATE=")
						fmt.Printf("网络状态更新: %s\n", stateStr)
						// 触发你的耗时函数
						// yourHeavyFunction()
					}
				}
			}
		case err, ok := <-watcher.Errors:
			if !ok {
				return
			}
			fmt.Fprintln(os.Stderr, "监听器错误:", err)
		}
	}
}

方案对比

  • DBus方式:官方标准,支持获取详细事件(如具体连接信息),实时性强,适合精准触发场景。
  • inotify文件监听:实现简单,无需了解DBus协议,但仅能获取全局状态,信息有限,且文件更新可能存在轻微延迟。

内容的提问来源于stack exchange,提问作者Amirography

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 10:39:32