inotify_add_watch 在 /sys/class/net/eth0/operstate 上失败
Posted
技术标签:
【中文标题】inotify_add_watch 在 /sys/class/net/eth0/operstate 上失败【英文标题】:inotify_add_watch fails on /sys/class/net/eth0/operstate 【发布时间】:2014-10-31 10:25:38 【问题描述】:我在 Linux 中使用了 inotify,以便在网络接口链接更改时引发事件。每当接口链接更改时,/sys/class/net/eth40/operstate/ 文件就会被修改。但是在下面的代码sn-p中,即使文件被修改,读取功能仍然处于阻塞状态。
#include <stdio.h>
#include <sys/inotify.h>
#include <stdlib.h>
#include <limits.h>
#include <signal.h>
#define FILE_TO_WATCH "/sys/class/net/eth40/operstate"
#define EVENT_SIZE (sizeof (struct inotify_event))
#define EVENT_BUFFER_LENGTH (1024 * EVENT_SIZE + NAME_MAX + 1)
void print_event(struct inotify_event *event)
int ret = 0;
if (event->mask & IN_CREATE)
printf("file created in directory\n");
if (event->mask & IN_DELETE)
printf("file deleted in directory\n");
if (event->mask & IN_ACCESS)
printf("file accessed\n");
if (event->mask & IN_CLOSE)
printf("file closed after reading or writing \n");
if (event->mask & IN_OPEN)
printf("file opened\n");
if (event->len)
printf("name: %s\n", event->name);
int main(int argc, char** argv)
int notify_fd;
int watch_fd;
long input_len;
char *ptr;
char buffer[EVENT_BUFFER_LENGTH];
struct inotify_event *event;
notify_fd = inotify_init();
if (notify_fd < 0)
perror("cannot init inotify");
exit(EXIT_FAILURE);
printf("done1\n");
watch_fd = inotify_add_watch(notify_fd,FILE_TO_WATCH,IN_ACCESS|IN_MODIFY);
if (watch_fd < 0)
perror("cannot add file");
exit(EXIT_FAILURE);
printf("done2\n");
while (1)
input_len = read(notify_fd, buffer, EVENT_BUFFER_LENGTH);
if (input_len <= 0)
perror("error reading from inotify fd");
exit(EXIT_FAILURE);
printf("done3\n");
ptr = buffer;
while (ptr < buffer + input_len)
event = (struct inotify_event *) ptr;
print_event(event);
ptr += sizeof (struct inotify_event) +event->len;
我错过了什么吗?
【问题讨论】:
【参考方案1】:/sys 不是一个普通的文件系统,而是一个特殊的内存文件系统,叫做sysfs
引用kernel developer:
inotify 不会也不会在 sysfs 上工作。或procfs。或开发人员。 或任意数量的网络文件系统。不管一个人多么努力 可能希望它工作,这根本不可行。
对于网络链接事件,您可以使用 rtnetlink,虽然这样的内容几乎没有文档记录,但这里有一个起点示例,将向您展示链接(和其他一些)事件,您必须弄清楚哪些事件/flags 和与您的特定情况相关的类似内容。
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <asm/types.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/if.h>
#include <linux/rtnetlink.h>
#define ENTRY(x) x, #x
struct
unsigned flag;
const char *name;
ifi_flag_map[] =
ENTRY(IFF_UP),
ENTRY(IFF_BROADCAST),
ENTRY(IFF_DEBUG),
ENTRY(IFF_LOOPBACK),
ENTRY(IFF_POINTOPOINT),
ENTRY(IFF_NOTRAILERS),
ENTRY(IFF_RUNNING),
ENTRY(IFF_NOARP),
ENTRY(IFF_PROMISC),
ENTRY(IFF_ALLMULTI),
ENTRY(IFF_MASTER),
ENTRY(IFF_SLAVE),
ENTRY(IFF_MULTICAST),
ENTRY(IFF_PORTSEL),
ENTRY(IFF_AUTOMEDIA),
ENTRY(IFF_DYNAMIC),
ENTRY(IFF_LOWER_UP),
ENTRY(IFF_DORMANT),
ENTRY(IFF_ECHO),
;
struct
unsigned type;
const char *name;
nlmrt_type_map[] =
ENTRY(RTM_NEWLINK ),
ENTRY(RTM_DELLINK),
ENTRY(RTM_GETLINK),
ENTRY(RTM_SETLINK),
ENTRY(RTM_NEWADDR ),
ENTRY(RTM_DELADDR),
ENTRY(RTM_GETADDR),
ENTRY(RTM_NEWROUTE ),
ENTRY(RTM_DELROUTE),
ENTRY(RTM_GETROUTE),
ENTRY(RTM_NEWNEIGH ),
ENTRY(RTM_DELNEIGH),
ENTRY(RTM_GETNEIGH),
ENTRY(RTM_NEWRULE ),
ENTRY(RTM_DELRULE),
ENTRY(RTM_GETRULE),
ENTRY(RTM_NEWQDISC ),
ENTRY(RTM_DELQDISC),
ENTRY(RTM_GETQDISC),
ENTRY(RTM_NEWTCLASS ),
ENTRY(RTM_DELTCLASS),
ENTRY(RTM_GETTCLASS),
ENTRY(RTM_NEWTFILTER ),
ENTRY(RTM_DELTFILTER),
ENTRY(RTM_NEWACTION ),
ENTRY(RTM_DELACTION),
ENTRY(RTM_GETACTION),
ENTRY(RTM_NEWPREFIX ),
ENTRY(RTM_GETMULTICAST ),
ENTRY(RTM_GETANYCAST ),
ENTRY(RTM_NEWNEIGHTBL ),
ENTRY(RTM_GETNEIGHTBL ),
ENTRY(RTM_SETNEIGHTBL),
ENTRY(RTM_NEWNDUSEROPT ),
ENTRY(RTM_NEWADDRLABEL ),
ENTRY(RTM_DELADDRLABEL),
ENTRY(RTM_GETADDRLABEL),
ENTRY(RTM_GETDCB ),
ENTRY(RTM_SETDCB),
ENTRY(RTM_NEWNETCONF ),
ENTRY(RTM_GETNETCONF ),
ENTRY(RTM_NEWMDB ),
ENTRY(RTM_DELMDB ),
ENTRY(RTM_GETMDB ),
;
void print_type(unsigned type)
size_t i;
for (i = 0; i < sizeof nlmrt_type_map/sizeof nlmrt_type_map[0]; i++)
if (type == nlmrt_type_map[i].type)
printf("\t\tMsg Type: %s\n", nlmrt_type_map[i].name);
return;
printf("\t\tMsg Type: unknown(%d)\n", type);
void print_flags(unsigned flags, unsigned change)
size_t i;
printf("\t\tflags: ");
for (i = 0; i < sizeof ifi_flag_map/sizeof ifi_flag_map[0]; i++)
if (flags & ifi_flag_map[i].flag)
if (change & ifi_flag_map[i].flag)
printf("%s(C) ", ifi_flag_map[i].name);
else
printf("%s ", ifi_flag_map[i].name);
puts("");
oid read_msg(int fd)
int len;
char buf[4096];
struct iovec iov = buf, sizeof(buf) ;
struct sockaddr_nl sa;
struct msghdr msg = (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 ;
struct nlmsghdr *nh;
len = recvmsg(fd, &msg, 0);
if(len == -1)
perror("recvmsg");
return;
for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
nh = NLMSG_NEXT (nh, len))
struct ifinfomsg *ifimsg;
/* The end of multipart message. */
printf("netlink message: len = %u, type = %u, flags = 0x%X, seq = %u, pid = %u\n",
nh->nlmsg_len,
nh->nlmsg_type,
nh->nlmsg_flags,
nh->nlmsg_seq,
nh->nlmsg_pid);
if (nh->nlmsg_type == NLMSG_DONE)
return;
if (nh->nlmsg_type == NLMSG_ERROR)
continue;
ifimsg = NLMSG_DATA(nh);
printf("\tifi_family = %u, ifi_type = %u, ifi_index = %u, ifi_flags = 0x%X, ifi_change = 0x%X\n",
ifimsg->ifi_family ,
ifimsg->ifi_type ,
ifimsg->ifi_index ,
ifimsg->ifi_flags ,
ifimsg->ifi_change);
print_type(nh->nlmsg_type);
print_flags(ifimsg->ifi_flags, ifimsg->ifi_change);
int main(int argc, char *argv[])
struct sockaddr_nl sa;
int fd;
memset(&sa, 0, sizeof(sa));
sa.nl_family = AF_NETLINK;
sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if(fd == -1)
perror("socket");
return 1;
if(bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1)
perror("bind");
return 1;
for(;;)
read_msg(fd);
return 0;
【讨论】:
您能否建议我使用其他方法来监控 NIC 端口上的网络链接事件。 有什么方法可以在c中实现windows中的网络链接事件吗? @MujtabaMohd 可能。您可以在检查是否已在 *** 上询问或检查 MSDN 文档以获得简单的解决方案后提出一个新问题。以上是关于inotify_add_watch 在 /sys/class/net/eth0/operstate 上失败的主要内容,如果未能解决你的问题,请参考以下文章
为啥需要使用 inotify_add_watch() 调用 read() 两次
inotify_add_watch 失败,没有这样的文件或目录
推送到 bitbucket 时出现错误“inotify_add_watch”
inotify,inotify_add_watch() 监控多个目录,c++
inotify_add_watch 相对于 O_PATH dirfd
Docker 守护进程无法启动:inotify_add_watch: no such file or directory