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
相关产品推荐
相关产品推荐

