通知丢失的事件

Posted

技术标签:

【中文标题】通知丢失的事件【英文标题】:inotify missing events 【发布时间】:2013-04-04 08:48:00 【问题描述】:

我想监控我系统上的 USB 密钥。我知道它们总是挂载在 /media 中,所以我使用 inotify 来监控 /media。一些 USB 密钥在插入时会创建一个文件夹(例如 sda),该文件夹会一直保留到它们被拔出,有些则创建一个文件夹(例如 sda),立即删除它并创建一个新文件夹(例如 sda1)。这是由于键上的分区。

但是,有时 inotify 仅捕获创建和删除第一个文件夹的事件,而错过了第二个文件夹的创建。当我手动检查 /media 时,第二个文件夹存在,但从未被 inotify 通知。

这种情况很少发生,当它发生时,它总是在设备重启后的第一个插头处。

#include <sys/inotify.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

/* size of the event structure, not counting name */
#define EVENT_SIZE  (sizeof (struct inotify_event))

/* reasonable guess as to size of 32 events */
#define BUF_LEN        (32 * (EVENT_SIZE + 16))

int main(int argc, char **argv) 
    int fd,wd,len,i;
    char buf[BUF_LEN];
    struct inotify_event *event;
    fd_set watch_set;

    fd = inotify_init();
    if (fd < 0) 
        perror("init failed");
        exit(EXIT_FAILURE);
    

    wd = inotify_add_watch(fd,"/media",IN_ALL_EVENTS);
    if (wd < 0) 
        perror("add watch failed");
        exit(EXIT_FAILURE);
    

    /* put the file descriptor to the watch list for select() */
    FD_ZERO(&watch_set);
    FD_SET(fd,&watch_set);

    while(1) 
        select(fd+1,&watch_set,NULL,NULL,NULL);
        len = read(fd,buf,BUF_LEN);
        i=0;
        while(i < len) 

            event = (struct inotify_event *) &buf[i];

            if ((event->mask & IN_CREATE) != 0) 
                printf ("%s created\n",event->name);
            
            else if ((event->mask & IN_DELETE) != 0) 
                printf ("%s deleted\n",event->name);
            
            else 
                printf ("wd=%d mask=0x%X cookie=%u len=%u name=%s\n",
                                event->wd, event->mask,
                                event->cookie, event->len, event->name);
            

            i += EVENT_SIZE + event->len;

        

    


有什么想法吗?

【问题讨论】:

是否可以删除与***.com/questions/15350369/how-to-use-inotify-in-c 相关的/media 并创建一个新的/media 而没有为其创建新的inotify_add_watch 只创建和删除 /media 的子文件夹。虽然错过了一个事件,但下一个事件又被抓住了。所以手表还在运行。 【参考方案1】:

inotify 的子文件夹问题众所周知并且很容易重现:

    启动 inotifywait 观察一个空的 tmp 目录:

    inotifywait -e create -m -r --format '%:e %f' ./tmp

    在另一个shell中输入:

    mkdir tmp/0 tmp/0/0 tmp/0/0/0 tmp/0/0/0/0

    您很可能只会收到第一个子目录的通知。

    创建:ISDIR 0

在创建目录、您的应用程序收到通知以及添加新的 inotify 监视之间丢失事件(特别是子目录创建事件)的明显可能性,使得递归监控过于不可靠。唯一安全的选择是扫描新创建目录的内容。

来自限制和警告下的inotify doc:

如果监视整个目录子树,并且新的子目录是 在该树中创建,请注意,在您创建手表时 新的子目录,新文件可能已经在 子目录。因此,您可能需要扫描 添加手表后立即创建子目录。

【讨论】:

仔细看bad的问题,他只关心一个目录级别,所以上面的不适用。 但是,再深入一点,这可能不是坏人想要的:fd = inotify_init();如果使用 select,这应该是: fd = inotify_init1(IN_NONBLOCK);使用 select,立即接收子目录事件,而不是缓冲。 正如你所提到的,子目录并不是让我担心的,我只对一个目录级别的事件感兴趣。但是,同时我发现这是 inotify 的一个已知问题(请参阅我的回答)【参考方案2】:

与此同时,我发现这是 inotify 的一个已知问题。如果两个事件几乎同时出现,则 inotify 只捕获其中一个。 我的解决方案:我不再使用inotify,而是使用libudev来监控插入机器的设备......

【讨论】:

这个问题在任何地方都有描述吗?【参考方案3】:

    您可以使用inotifywait 命令(来自inotify-tools 包)监视/media 目录,以检查您感兴趣的inotify 事件是否发生. 参考:http://www.noah.org/wiki/Inotify,_FAM,_Gamin#Examples_with_inotify-tools

    如果inotify 确实错过了事件,原因可能是:Inotify 确实报告了sysfsprocfs 中的部分但不是全部事件。 (嗯,我不能肯定。只是我的猜测。)

参考:http://en.wikipedia.org/wiki/Inotify#Limitationshttp://en.wikipedia.org/wiki/Sysfshttp://en.wikipedia.org/wiki/Procfs

【讨论】:

以上是关于通知丢失的事件的主要内容,如果未能解决你的问题,请参考以下文章

通过调用Local Method响应Vue.js事件总线时丢失上下文

我订阅标签后如何知道plc连接是否丢失?

Firebase 静默通知丢失 (iOS)

Cordova - 关闭通知将丢失其中的数据

Android 实时多人游戏通知连接丢失

在通知单击时启动 Fragment 而不会丢失状态