linux c++实现监控网卡状态变化
第一部分:网卡状态变化监控实现
在 Linux 上实现一个监控网卡状态变化的 C++ 线程,可以通过使用 Linux 系统中的 netlink 套接字来实现。netlink 是一种与内核通信的机制,通过 NETLINK_ROUTE,我们可以实时监听网卡状态的变化,比如 UP 和 DOWN 状态。
以下是一个示例代码,展示如何用 C++ 创建一个线程来监控网络接口的状态变化:
示例代码
#include <iostream>
#include <thread>
#include <atomic>
#include <unistd.h>
#include <netlink/netlink.h>
#include <sys/socket.h>
#include <linux/rtnetlink.h>
// 全局变量用来控制线程退出
std::atomic<bool> running{true};
// 处理网络事件的函数
void handle_netlink_message(struct nlmsghdr *nlh) {
struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nlh);
// 提取网卡名称
int len = nlh->nlmsg_len;
struct rtattr *attr = IFLA_RTA(ifi);
int attr_len = IFLA_PAYLOAD(nlh);
char ifname[IF_NAMESIZE] = {0};
for (; RTA_OK(attr, attr_len); attr = RTA_NEXT(attr, attr_len)) {
if (attr->rta_type == IFLA_IFNAME) {
strncpy(ifname, (char *)RTA_DATA(attr), RTA_PAYLOAD(attr));
break;
}
}
// 判断网卡状态
if (ifi->ifi_flags & IFF_RUNNING) {
std::cout << "Interface " << ifname << " is UP." << std::endl;
} else {
std::cout << "Interface " << ifname << " is DOWN." << std::endl;
}
}
// 监控网卡状态变化的线程函数
void monitor_interface_status() {
int sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock_fd < 0) {
std::cerr << "Failed to create socket." << std::endl;
return;
}
struct sockaddr_nl addr = {};
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_LINK; // 监听网络链路的变化
if (bind(sock_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
std::cerr << "Failed to bind socket." << std::endl;
close(sock_fd);
return;
}
char buffer[4096];
while (running) {
ssize_t len = recv(sock_fd, buffer, sizeof(buffer), 0);
if (len < 0) {
if (running) {
std::cerr << "Error receiving netlink message." << std::endl;
}
break;
}
struct nlmsghdr *nlh;
for (nlh = (struct nlmsghdr *)buffer; NLMSG_OK(nlh, len);
nlh = NLMSG_NEXT(nlh, len)) {
if (nlh->nlmsg_type == NLMSG_DONE) {
break;
}
if (nlh->nlmsg_type == RTM_NEWLINK) {
handle_netlink_message(nlh);
}
}
}
close(sock_fd);
}
int main() {
// 创建监控线程
std::thread monitor_thread(monitor_interface_status);
std::cout << "Monitoring network interface status. Press Enter to stop..." << std::endl;
std::cin.get(); // 等待用户输入
// 停止监控
running = false;
monitor_thread.join();
std::cout << "Monitoring stopped." << std::endl;
return 0;
}
代码说明
-
netlink套接字-
使用
AF_NETLINK套接字与 Linux 内核通信。 -
注册组
RTMGRP_LINK来监听网络接口状态的改变。
-
-
ifinfomsg结构-
包含网络接口的状态信息,可以通过
ifi_flags判断接口是否是UP或DOWN。
-
-
线程的创建
-
用 C++ 的
std::thread创建独立的线程,用于运行网络状态监控逻辑。
-
-
优雅退出
-
使用
std::atomic<bool>变量running来通知线程安全地结束。
-
-
网卡名称提取
-
当系统发送网络变化事件时,使用
IFLA_IFNAME从rtattr结构中提取网卡名称。
-
编译和运行
将代码保存为 monitor_net.cpp 并编译:
g++ -std=c++11 -o monitor_net monitor_net.cpp
运行代码:
./monitor_net
当有网卡状态变化(例如 ifconfig eth0 down 或 ifconfig eth0 up)时,程序会输出网卡的状态信息。
示例输出
Monitoring network interface status. Press Enter to stop...
Interface eth0 is DOWN.
Interface eth0 is UP.
Interface wlan0 is DOWN.
...
注意事项
-
需要以
root权限运行程序,否则可能没有权限监听netlink消息。 -
如果使用 CMake 构建系统,可以增加
target_link_libraries选项链接相关库(如 netlink)。 -
程序能运行在基于 Linux 的系统上,但在非 Linux 系统上不可用。
通过这个实现,你可以实时监控网卡状态的改变,并在实际场景中根据状态变化执行不同的逻辑处理。
第二部分:ifi_flags标志
在 Linux 中,ifi->ifi_flags 是 ifinfomsg 结构的一个字段,它表示网络接口的状态标志。其值由 IFF_* 宏定义,这些宏在头文件 <net/if.h> 中定义。
ifi_flags 是一个位标志,可以同时包含多个值(通过按位或的方式组合)。以下是常用的 IFF_* 标志及其含义的列表:
常用 IFF_* 标志
-
IFF_UP(0x1)-
表示接口是激活的(已启动)。
-
如果未设置此标志,接口被标记为关闭。
-
-
IFF_BROADCAST(0x2)-
表示接口支持广播,并有有效的广播地址。
-
-
IFF_DEBUG(0x4)-
用于启用调试信息(很少使用)。
-
-
IFF_LOOPBACK(0x8)-
表示此接口是一个回环接口(如
lo内置回环接口)。
-
-
IFF_POINTOPOINT(0x10)-
表示接口是一个点对点连接(如 PPP 连接)。
-
-
IFF_NOTRAILERS(0x20)-
禁止使用 trailer 协议(旧功能,现代设备中已很少使用)。
-
-
IFF_RUNNING(0x40)-
表示接口已经就绪,能够正常工作(链路层状态是 UP)。
-
和
IFF_UP的区别是:IFF_UP表示接口被管理员标记为启用,而IFF_RUNNING表示接口实际上可以运行(例如网线已插入)。
-
-
IFF_NOARP(0x80)-
表示接口不使用 ARP 协议。
-
-
IFF_PROMISC(0x100)-
表示接口处于混杂模式(Promiscuous Mode):接收所有数据包,而不论目标是否是该接口(用于抓包工具如 Wireshark)。
-
-
IFF_ALLMULTI(0x200)-
表示接口接收所有的多播数据包。
-
-
IFF_MASTER(0x400)-
表示接口是一个主设备(例如,在网桥或绑定设备配置中)。
-
-
IFF_SLAVE(0x800)-
表示接口是一个从设备(例如,在绑定中)。
-
-
IFF_MULTICAST(0x1000)-
表示接口支持多播。
-
-
IFF_PORTSEL(0x2000)-
接口能够选择媒介类型(指支持多种介质的网络接口)。
-
-
IFF_AUTOMEDIA(0x4000)-
表示接口将自动检测媒介类型。
-
-
IFF_DYNAMIC(0x8000)-
动态接口标志。
-
如何检查 ifi->ifi_flags 值
由于 ifi_flags 是位标志,可以通过按位与 (&) 操作检查特定标志。例如:
if (ifi->ifi_flags & IFF_RUNNING) {
std::cout << "Interface is running (link is up)." << std::endl;
}
if (ifi->ifi_flags & IFF_UP) {
std::cout << "Interface is enabled (administratively up)." << std::endl;
}
接口状态下的典型组合
-
接口已启用且运行
-
IFF_UP | IFF_RUNNING -
表示接口被管理员标记为启用 (
IFF_UP),并且链路层链路是正常的(如网线已插入,IFF_RUNNING)。
-
-
接口已启用但未运行
-
IFF_UP(无IFF_RUNNING) -
表示接口被管理员启用,但可能未插入网线或连接有问题。
-
-
接口被禁用
-
无
IFF_UP标志。 -
表示接口处于关闭状态。
-
实际使用场景
通过检查这些状态标志,可以判断网络接口的当前状态,执行不同的逻辑。例如:
-
检查是否网线断开:
if (!(ifi->ifi_flags & IFF_RUNNING)) { std::cout << "Network cable is unplugged or link is down." << std::endl; } -
判断是否支持混杂模式:
if (ifi->ifi_flags & IFF_PROMISC) { std::cout << "Interface is in promiscuous mode." << std::endl; }
总结
ifi->ifi_flags 是描述网络接口状态的一个重要字段。通过位标志的形式,可以准确地判断接口的当前特性和状态,例如是否已启动、是否运行、多播、广播能力等。这在网络开发和调试中非常有用。
更多推荐

所有评论(0)