zoukankan      html  css  js  c++  java
  • linux内核的INotify接口机制

    inotify(7) - Linux manual page https://www.man7.org/linux/man-pages/man7/inotify.7.html

    监听风云1 - inotify 介绍 https://mp.weixin.qq.com/s?src=11&timestamp=1642038821&ver=3555&signature=rK1263NwTIZlT3uoI*1voiTuGbbo8Ex0NgNC*2wa2vzFPD*qLVLorBB3emfhopgkHDTy8m4*W3gvwO3Jf9ZYcgXDMTb62G5glhV79d578tNKq-c9DRzoj*vjdmH2ee6u&new=1

    不知道大家用过 Dropbox 没有,这是国外一款非常好用云盘,你只需要在 Dropbox 中设置好要同步的目录,每当此目录中的文件发生变动时,Dropbox 就会自动把文件同步到云端。

    图片

    那么,Dorpbox 是怎么知道目录的文件发生了改变呢?答案是,通过 inotfiy 这个系统功能来实现的。

    我们主要分为两篇文章来介绍 inotify 这个功能:本篇首先介绍 inotify 的使用方式,而下篇主要介绍 inotify 的实现原理。

    inotify 接口们

    其实 inotify 的接口比较少,只有3个:inotify_initinotify_add_watchinotify_rm_watch。下面我们介绍一下这三个接口的作用和原型。

    1. inotify_init

    inotify_init 函数用于创建一个 inotify 的句柄,可以认为此句柄就是 inotify 的对象。其原型如下:

    
    
    int inotify_init(void);

    2. inotify_add_watch

    创建好 inotify 句柄后,就可以通过调用 inotify_add_watch 函数添加要进行监听的文件或者目录。其原型如下:

    
    
    int inotify_add_watch(int fd, const char *path, uint32_t mask);
     

    inotify_add_watch 调用成功后,会返回被监听文件或目录的描述符。下面介绍一下各个参数的意义:

    • fd:就是通过 inotify_init 函数创建的 inotify 句柄。

    • path:要监听的文件或目录的路径。

    • mask:要监听的事件,其事件类型如下:

      • 类型描述
        IN_ACCESS 文件被访问
        IN_ATTRIB 文件元数据改变
        IN_CLOSE_WRITE 关闭为了写入而打开的文件
        IN_CLOSE_NOWRITE 关闭只读方式打开的文件
        IN_CREATE 在监听目录内创建了文件/目录
        IN_DELETE 在监听目录内删除文件/目录
        IN_DELETE_SELF 监听目录/文件本身被删除。
        IN_MODIFY 文件被修改
        IN_MOVE_SELF 受监控目录/文件本身被移动
        IN_MOVED 文件被移
        IN_OPEN 文件被打开
        IN_ALL_EVENTS 以上所有输出事件的统称

    3. inotify_rm_watch

    inotify_rm_watch 函数用于删除被监听的文件或目录,其原型如下:

    
    
    int inotify_rm_watch(int fd, uint32_t wd);
     

    下面介绍一下各个参数的意义:

    • fd:调用 inotify_init 函数返回的 inotify 句柄。

    • wd:由 inotify_add_watch 函数的返回被监听文件或目录的描述符。

    读取变动事件

    介绍完 inotify 的接口后,现在通过一个简单的例子来展示怎么使用 inotify。在编写 inotify 的实例前,先介绍一下怎么获取被监听文件或目录的变动事件。inotify 并没有提供特定的接口来获取被监听的文件或目录的变动事件,而是通过通用的 read 函数来读取,我们来看看 read 函数的原型:

    
    
    int read(int fd, void *events, size_t len);
     

    下面说说各个参数的意义:

    • fd:由 inotify_init 创建的 inotify 句柄。

    • events:存放变动事件的缓冲区。

    • len:缓冲区的大小。

    events 参数用于存放被监听文件或目录的变动事件,一般指定为 inotify_event 结构的数组,inotify_event 结构的定义如下:

    
    
    struct inotify_event {
       int         wd;      // 被监控文件或目录的描述符(由inotify_add_watch)
       uint32_t    mask;    // 变动的事件
       uint32_t    cookie;  // 比较少使用,可以忽略
       uint32_t    len;     // name的长度
       char        name[];  // 用于存放发生变动的文件或目录名称
    };
     

    使用实例

    现在我们可以使用 inotify 来编写实例了,这个实例主要介绍怎么使用 inotify 监听一个文件或者目录,并且打印其变动事件。

    实现代码如下:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/inotify.h>  // 引入 inotify 的头文件

    /*
    * 用于打印发生的事件
    */
    void display_event(const char *base, struct inotify_event *event)
    {
       char *operate;
       int mask = event->mask;

       if (mask & IN_ACCESS)        operate = "ACCESS";
       if (mask & IN_ATTRIB)        operate = "ATTRIB";
       if (mask & IN_CLOSE_WRITE)   operate = "CLOSE_WRITE";
       if (mask & IN_CLOSE_NOWRITE) operate = "CLOSE_NOWRITE";
       if (mask & IN_CREATE)        operate = "CREATE";
       if (mask & IN_DELETE_SELF)   operate = "DELETE_SELF";
       if (mask & IN_MODIFY)        operate = "MODIFY";
       if (mask & IN_MOVE_SELF)     operate = "MOVE_SELF";
       if (mask & IN_MOVED_FROM)    operate = "MOVED_FROM";
       if (mask & IN_MOVED_TO)      operate = "MOVED_TO";
       if (mask & IN_OPEN)          operate = "OPEN";
       if (mask & IN_IGNORED)       operate = "IGNORED";
       if (mask & IN_DELETE)        operate = "DELETE";
       if (mask & IN_UNMOUNT)       operate = "UNMOUNT";

       printf("%s/%s: %s\n", base, event->name, operate);
    }

    #define EVENTS_BUF_SIZE 4096

    int main(int argc, char const *argv[])
    {
       int fd;
       int nbytes, offset;
       char events[EVENTS_BUF_SIZE];
       struct inotify_event *event;

       fd = inotify_init(); // 创建 inotify 句柄
       if (fd < 0) {
           printf("Failed to initalize inotify\n");
           return -1;
      }

       // 从命令行参数获取要监听的文件或目录路径
       // 添加要监听的文件或者目录, 监听所有事件
       if (inotify_add_watch(fd, argv[1], IN_ALL_EVENTS) == -1) {
           printf("Failed to add file or directory watch\n");
           return -1;
      }

       for (;;) {
           memset(events, 0, sizeof(events));

           // 读取发生的事件
           nbytes = read(fd, events, sizeof(events));
           if (nbytes <= 0) {
               printf("Failed to read events\n");
               continue;
          }

           // 开始打印发生的事件
           for (offset = 0; offset < nbytes; ) {
               event = (struct inotify_event *)&events[offset]; // 获取变动事件的指针

               display_event(argv[1], event);

               offset += sizeof(struct inotify_event) + event->len; // 获取下一个变动事件的偏移量
          }
      }

       return 0;
    }
     

    上面的实例逻辑比较简单,主要步骤如下:

    • 调用 inotify_init 函数创建一个 inotify 句柄。

    • 从命令行中获取要监听的文件或目录路径,并且通过 inotify_add_watch 函数把其添加到 inotify 中进行监听。

    • 在一个无限循环中,通过 read 函数读取被监听的文件或目录的变动事件,并且通过调用 display_event 函数打印事件。

    上面实例比较难懂的就是从 events 参数中获取变动事件的指针,我们可以通过下面这幅图来理清获取变动事件指针的逻辑:

    图片

    通过上图,就比较容易理解怎么从 events 缓冲区中获取到变动事件的指针了。

    最后,来看看我们编写的实例的效果动画:

    图片

    总结

    本文主要介绍 inotify 的使用,在下一篇文章中,我们将会介绍 inotify 的原理和实现,敬请期待(当然对 inotify 的实现没兴趣的就不用期待了...)。

     实时备份工具之inotify+rsync https://mp.weixin.qq.com/s?src=11&timestamp=1642038821&ver=3555&signature=PGgYN9fNSOIjZMqF66TAqO8rUZDaNReLiOf6P16HSLI0Iaawsj*n6MLdwlaDP-sBwZzRSfoZbht5rMeUV8jJGk2Uyg-Yp4G4RfAr67CClTW2mC45pp3o6f9ml7BDMoLb&new=1

    实时备份工具之inotify+rsync https://mp.weixin.qq.com/s?src=11&timestamp=1642038821&ver=3555&signature=PGgYN9fNSOIjZMqF66TAqO8rUZDaNReLiOf6P16HSLI0Iaawsj*n6MLdwlaDP-sBwZzRSfoZbht5rMeUV8jJGk2Uyg-Yp4G4RfAr67CClTW2mC45pp3o6f9ml7BDMoLb&new=1

    浅析gowatch监听文件变动实现原理 - 知乎 https://zhuanlan.zhihu.com/p/341969415

  • 相关阅读:
    洛谷 1850 NOIP2016提高组 换教室
    2018牛客多校第三场 C.Shuffle Cards
    2018牛客多校第一场 B.Symmetric Matrix
    2018牛客多校第一场 A.Monotonic Matrix
    2018牛客多校第一场 D.Two Graphs
    2018宁夏邀请赛L Continuous Intervals
    2018宁夏邀请赛K Vertex Covers
    BZOJ
    HDU
    ACM International Collegiate Programming Contest, Egyptian Collegiate Programming Contest (ECPC 2015)
  • 原文地址:https://www.cnblogs.com/rsapaper/p/15792655.html
Copyright © 2011-2022 走看看