如何在不查询内核的情况下监控C程序中的NIC状态(up / down)?

现在我需要实时获取NIC的状态(向上或向下)。 这意味着当NIC在阻塞的循环中上下移动时,我必须捕获内核中断。

我的第一个愚蠢的方法是检查/ sys / class / net / eth0 / operstate或使用ioctl在循环中每隔100ms获取ifflag。 但100ms太长的应用程序重新路由stream量,每100ms轮询内核也不是好主意。

一旦我注意到可以在块模式下监视文件的inotify函数。 但不幸的是,它不能监视/ sys / class / net / eth0 / operstate文件,因为/ sys位于不在磁盘中的RAM中。

那么,除了编写一个内核模块来捕捉C程序中的NIC中断(up / down)以外,还有其他方法吗?

是的,打开一个netlink套接字,并听取RTMGRP_LINK(网络接口创建/删除/向上/向下事件)组播组。

这里的netlink手册页有一个具体的例子来做到这一点。

在网上做了一些研究/阅读之后,我设法制作了一个工作代码来监视网卡的状态。

 #include <asm/types.h> #include <sys/socket.h> #include <unistd.h> #include <errno.h> #include <stdio.h> #include <string.h> #include <net/if.h> #include <netinet/in.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #include <stdlib.h> #include <sys/time.h> #include <sys/types.h> int read_event (int sockint) { int status; int ret = 0; char buf[4096]; struct iovec iov = { buf, sizeof buf }; struct sockaddr_nl snl; struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 }; struct nlmsghdr *h; struct ifinfomsg *ifi; status = recvmsg (sockint, &msg, 0); if (status < 0) { /* Socket non-blocking so bail out once we have read everything */ if (errno == EWOULDBLOCK || errno == EAGAIN) return ret; /* Anything else is an error */ printf ("read_netlink: Error recvmsg: %d\n", status); perror ("read_netlink: Error: "); return status; } if (status == 0) { printf ("read_netlink: EOF\n"); } // We need to handle more than one message per 'recvmsg' for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status); h = NLMSG_NEXT (h, status)) { //Finish reading if (h->nlmsg_type == NLMSG_DONE) return ret; // Message is some kind of error if (h->nlmsg_type == NLMSG_ERROR) { printf ("read_netlink: Message is an error - decode TBD\n"); return -1; // Error } if (h->nlmsg_type == RTM_NEWLINK) { ifi = NLMSG_DATA (h); printf ("NETLINK::%s\n", (ifi->ifi_flags & IFF_RUNNING) ? "Up" : "Down"); } } return ret; } int main (int argc, char *argv[]) { fd_set rfds, wfds; struct timeval tv; int retval; struct sockaddr_nl addr; int nl_socket = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (nl_socket < 0) { printf ("Socket Open Error!"); exit (1); } memset ((void *) &addr, 0, sizeof (addr)); addr.nl_family = AF_NETLINK; addr.nl_pid = getpid (); addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR; // addr.nl_groups = RTMGRP_LINK; if (bind (nl_socket, (struct sockaddr *) &addr, sizeof (addr)) < 0) { printf ("Socket bind failed!"); exit (1); } while (1) { FD_ZERO (&rfds); FD_CLR (nl_socket, &rfds); FD_SET (nl_socket, &rfds); tv.tv_sec = 10; tv.tv_usec = 0; retval = select (FD_SETSIZE, &rfds, NULL, NULL, &tv); if (retval == -1) printf ("Error select() \n"); else if (retval) { printf ("Event recieved >> "); read_event (nl_socket); } else printf ("## Select TimedOut ## \n"); } return 0; } 

您是否尝试使用selectpoll函数监视/sys/class/net/eth0/operstate文件? 据我所知, sysfs文件在轮询方面应该和普通文件一样:只要发生了变化,你就应该在文件句柄上得到一些通知,说明某些东西已经改变,你应该能够做出相应的反应。