# 如何用Linux C++编程监听网络事件

在 Linux C++ 程序里,要检测 网络恢复网络变化,常见有几种方法,取决于你是想检测物理链路变化(网卡 up/down)、IP/路由变化,还是真正的网络可达性变化。


Linux 提供了 netlink(尤其是 RTNETLINK)机制,可以订阅网络接口、IP 地址、路由表等变化事件,而不需要轮询。 优点:实时、无需 root、系统级事件源。

核心步骤:

  1. 创建 NETLINK_ROUTE 类型的 netlink socket。
  2. 订阅 RTMGRP_LINK(链路事件)、RTMGRP_IPV4_IFADDR(IPv4 地址变化)、RTMGRP_IPV6_IFADDR 等多播组。
  3. 解析 struct nlmsghdr 中的消息,判断接口 up/down、IP 改变等。

示例代码(简化版):

#include <iostream>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <unistd.h>
#include <cstring>

int main() {
    int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (fd < 0) {
        perror("socket");
        return 1;
    }

    sockaddr_nl addr{};
    addr.nl_family = AF_NETLINK;
    addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;

    if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("bind");
        close(fd);
        return 1;
    }

    char buf[4096];
    while (true) {
        int len = recv(fd, buf, sizeof(buf), 0);
        if (len < 0) {
            perror("recv");
            continue;
        }

        for (nlmsghdr* nh = (nlmsghdr*)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
            if (nh->nlmsg_type == NLMSG_DONE) break;

            if (nh->nlmsg_type == RTM_NEWADDR) {
                std::cout << "IP 地址变化\n";
            } else if (nh->nlmsg_type == RTM_DELADDR) {
                std::cout << "IP 地址删除\n";
            } else if (nh->nlmsg_type == RTM_NEWLINK || nh->nlmsg_type == RTM_DELLINK) {
                std::cout << "网络接口变化(up/down)\n";
            }
        }
    }

    close(fd);
    return 0;
}

这种方式可以精准地捕捉“网线拔插”“Wi-Fi 连接/断开”“IP 更新”等。


libnl 封装了 netlink 通信,更易用。

sudo apt install libnl-3-dev libnl-genl-3-dev

用法类似,但解析消息更方便。


# 3. 使用 NetworkManager D-Bus API

如果你的系统用 NetworkManager 管理网络,可以通过 D-Bus 监听网络状态变化:

  • /org/freedesktop/NetworkManagerPropertiesChanged 信号会通知网络变化。
  • 可以判断 ConnectivityActiveConnection 状态。

适合桌面环境或依赖 NetworkManager 的系统,但不适用于嵌入式(可能没装 NM)。


# 4. 检测真正的网络可用性

上面的方法只能告诉你链路或配置变了,但不保证“能访问互联网”。 如果需要检测网络是否恢复,可以定时或在事件触发时做一次 ping 或 TCP 连接测试

system("ping -c 1 8.8.8.8 > /dev/null 2>&1");

或用 C++ socket 尝试连接一个已知可靠的服务器(如 DNS 53 端口)。


总结推荐方案:

  • 底层实时检测:用 netlink (RTNETLINK) 监听接口/IP/路由变化。
  • 需要跨发行版统一接口:用 NetworkManager D-Bus API
  • 需要确认互联网可达:结合 netlink 事件 + ping/连接测试
Last Updated: 8/16/2025, 9:37:55 PM