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

Ubuntu下C++程序通过DBus监听NetworkManager网络变更事件的实现方案问询

Ubuntu下C++程序通过DBus监听NetworkManager网络变更事件的实现方案问询

嘿,刚好我之前折腾过类似的需求,针对你要在Ubuntu上用C++通过DBus监听NetworkManager网络变更(连接/断开/切换网络)的需求,给你梳理一套可行的实现方案:

一、前提确认

你说得没错,Ubuntu默认预装NetworkManager,它确实通过D-Bus系统总线广播网络状态变更事件,完全能覆盖你要监听的场景——不管是系统连上网、断网,还是从WiFi切到以太网这类网络切换操作。

二、依赖准备

首先得装必要的开发库,打开终端跑这条命令:

sudo apt-get install libdbus-1-dev libnm-dev
  • libdbus-1-dev:DBus的C语言开发库,用来直接和DBus总线交互
  • libnm-dev:NetworkManager的官方开发库,封装了DBus的细节,用起来更省心

三、两种实现思路

思路1:直接用DBus C API(底层实现)

如果想自己控制DBus交互的细节,可以直接用DBus的原生API。核心是订阅NetworkManager的PropertiesChanged信号,当网络状态变化时,这个信号会被广播出来。

下面是一个简单的示例代码:

#include <dbus/dbus.h>
#include <iostream>
#include <cstring>

// 信号回调函数,处理NetworkManager的属性变更
void handle_network_change(DBusConnection* conn, DBusMessage* msg, void* user_data) {
    DBusMessageIter iter;
    const char* interface_name;
    DBusMessageIter dict_iter;

    // 解析信号参数:第一个参数是接口名,第二个是属性变更字典
    if (!dbus_message_iter_init(msg, &iter)) {
        std::cerr << "Failed to init message iterator" << std::endl;
        return;
    }

    dbus_message_iter_get_basic(&iter, &interface_name);
    dbus_message_iter_next(&iter);
    dbus_message_iter_recurse(&iter, &dict_iter);

    // 遍历属性变更字典,提取我们关心的属性
    char* key;
    DBusMessageIter value_iter;
    while (dbus_message_iter_get_arg_type(&dict_iter) == DBUS_TYPE_DICT_ENTRY) {
        dbus_message_iter_recurse(&dict_iter, &value_iter);
        dbus_message_iter_get_basic(&value_iter, &key);
        dbus_message_iter_next(&value_iter);

        // 比如监听"ActiveConnections"(当前活跃连接)变化
        if (strcmp(key, "ActiveConnections") == 0) {
            std::cout << "Active network connection changed!" << std::endl;
            // 这里可以进一步解析具体的连接信息
        }
        // 也可以监听"NetworkingEnabled"(网络是否启用)
        else if (strcmp(key, "NetworkingEnabled") == 0) {
            dbus_bool_t is_enabled;
            dbus_message_iter_get_basic(&value_iter, &is_enabled);
            std::cout << "Network status: " << (is_enabled ? "Connected" : "Disconnected") << std::endl;
        }

        dbus_message_iter_next(&dict_iter);
    }
}

int main() {
    DBusError err;
    DBusConnection* conn;
    int ret;

    // 初始化DBus错误对象
    dbus_error_init(&err);

    // 连接到系统总线(NetworkManager在系统总线上)
    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
    if (dbus_error_is_set(&err)) {
        std::cerr << "DBus connection error: " << err.message << std::endl;
        dbus_error_free(&err);
        return 1;
    }
    if (!conn) {
        std::cerr << "Failed to connect to DBus system bus" << std::endl;
        return 1;
    }

    // 注册信号匹配规则:监听NetworkManager主对象的PropertiesChanged信号
    const char* match_rule = "type='signal',interface='org.freedesktop.NetworkManager',member='PropertiesChanged'";
    ret = dbus_bus_add_match(conn, match_rule, &err);
    if (dbus_error_is_set(&err)) {
        std::cerr << "DBus match error: " << err.message << std::endl;
        dbus_error_free(&err);
        dbus_connection_unref(conn);
        return 1;
    }

    // 注册信号回调
    dbus_connection_add_filter(conn, (DBusHandleMessageFunction)handle_network_change, nullptr, nullptr);

    // 进入事件循环,等待信号
    std::cout << "Listening for network changes..." << std::endl;
    while (true) {
        dbus_connection_read_write(conn, 0);
        dbus_connection_dispatch(conn);
        // 短暂休眠,避免占用过高CPU
        usleep(100000);
    }

    dbus_connection_unref(conn);
    return 0;
}

编译这条命令:

g++ -o network_monitor network_monitor.cpp `pkg-config --cflags --libs dbus-1`

思路2:用NetworkManager官方库libnm(更简洁)

直接用DBus API有点繁琐,NetworkManager提供了libnm库,封装了所有DBus交互细节,用起来更高效,也更符合C++的开发习惯。

示例代码大概是这样的:

#include <nm-client.h>
#include <iostream>

// 连接状态变更回调
void connection_state_changed(NMClient* client, NMActiveConnection* active_conn, GParamSpec* pspec, gpointer user_data) {
    NMState state = nm_client_get_state(client);
    switch (state) {
        case NM_STATE_CONNECTED_GLOBAL:
            std::cout << "Network is connected globally!" << std::endl;
            break;
        case NM_STATE_DISCONNECTED:
            std::cout << "Network is disconnected!" << std::endl;
            break;
        case NM_STATE_CONNECTING:
            std::cout << "Connecting to network..." << std::endl;
            break;
        default:
            break;
    }
}

int main() {
    GError* err = nullptr;
    NMClient* client = nm_client_new(nullptr, &err);
    if (!client) {
        std::cerr << "Failed to create NMClient: " << err->message << std::endl;
        g_error_free(err);
        return 1;
    }

    // 监听NetworkManager的state属性变化
    g_signal_connect(client, "notify::state", G_CALLBACK(connection_state_changed), nullptr);

    // 进入GLib主循环(libnm依赖GLib的事件循环)
    GMainLoop* loop = g_main_loop_new(nullptr, FALSE);
    std::cout << "Listening for network changes with libnm..." << std::endl;
    g_main_loop_run(loop);

    g_main_loop_unref(loop);
    g_object_unref(client);
    return 0;
}

编译命令:

g++ -o nm_monitor nm_monitor.cpp `pkg-config --cflags --libs libnm`

四、注意事项

  • 权限问题:普通用户就能监听这些信号,不需要root权限
  • 事件覆盖:用libnm的话,还可以监听更细粒度的事件,比如具体WiFi连接的信号强度变化、IP地址变更等
  • 循环处理:两种方案都需要保持事件循环运行,否则无法接收信号

备注:内容来源于stack exchange,提问作者Vipul Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 09:20:29