Linux inotify + Epoll实现机制

  首先学习Inotify机制,就是Linux系统下对文件目录的监听,如果目录下有文件创建删除都可以被监听到,那这个有什么作用呢?

在Android Input系统中可以实现对设备热插拔的监听。我们先看一个简单的Demo

  

#include<stdio.h>  
#include<assert.h>  
#include<unistd.h>  
#include<stdlib.h>  
#include<errno.h>  
#include<string.h>  
#include<sys/types.h>  
#include<sys/inotify.h>  
#include<limits.h>  
#include<fcntl.h>  
  
  
#define BUF_LEN 1000  

void displayEvent(struct inotify_event* tempEvent)
{
    printf("mask = %d\n",tempEvent->mask); 

    //判断有哪些事件发生
    if(tempEvent->mask & IN_ACCESS)   printf("IN_ACCESS\n");  
    if(tempEvent->mask & IN_DELETE_SELF)   printf("IN_DELETE_SELF\n");  
    if(tempEvent->mask & IN_MODIFY)  printf("IN_MODIFY\n");  
    if(tempEvent->mask & IN_OPEN)   printf("IN_OPEN\n");

}



int main(int argc , char** argv)
{
    int mNotifyId , mWd;
    char mInfoBuf[BUF_LEN];
    ssize_t mNumRead;
    struct inotify_event * mTempEvent; 
    char* p; 
    
    if(argc < 2)
    {
       printf("argv error\n");
    }
    
	//创建inotify
    mNotifyId = inotify_init();
    if(mNotifyId == -1)
    {
       printf("notifyInit Failure\n");
    } 
   
    //添加对文件的监听
    mWd = inotify_add_watch(mNotifyId,argv[1],IN_ALL_EVENTS);
    if(mWd == -1)
    {
       printf("watch failure \n");
    }
     
    while(1)
    {
       //监听的路径是否有文件创建删除等消息
       mNumRead = read(mNotifyId,mInfoBuf,BUF_LEN);
       if(mNumRead == -1)
       {
          printf("read error\n");
       }
       for(p = mInfoBuf;p < mInfoBuf + mNumRead;)
       {
          mTempEvent = (struct inotify_event *)p;
          displayEvent(mTempEvent);
          p += sizeof(struct inotify_event) + mTempEvent->len;
       }

    }
    
    return 0;


}
  Inotify可以监听到哪些事件呢

     

	可以被监控的事件:
    有几种事件能够被监控。一些事件,比如 IN_DELETE_SELF 只适用于正在被监控的项目,而另一些,比如 IN_ATTRIB 或者 IN_OPEN 则只适用于监控过的项目,或者如果该项目是目录,则可以应用到其所包含的目录或文件。
    IN_ACCESS
    被监控项目或者被监控目录中的条目被访问过。例如,一个打开的文件被读取。
    IN_MODIFY
    被监控项目或者被监控目录中的条目被修改过。例如,一个打开的文件被修改。
    IN_ATTRIB
    被监控项目或者被监控目录中条目的元数据被修改过。例如,时间戳或者许可被修改。
    IN_CLOSE_WRITE
    一个打开的,等待写入的文件或目录被关闭。
    IN_CLOSE_NOWRITE
    一个以只读方式打开的文件或目录被关闭。
	IN_CLOSE
	一个掩码,可以很便捷地对前面提到的两个关闭事件(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)进行逻辑操作。
	IN_OPEN
	文件或目录被打开。
	IN_MOVED_FROM
	被监控项目或者被监控目录中的条目被移出监控区域。该事件还包含一个 cookie 来实现 IN_MOVED_FROM 与 IN_MOVED_TO 的关联。
	IN_MOVED_TO
	文件或目录被移入监控区域。该事件包含一个针对 IN_MOVED_FROM 的 cookie。如果文件或目录只是被重命名,将能看到这两个事件,如果它只是被移入或移出非监控区域,将只能看到一个事件。如果移动或重命名一个被监控项目,监控将继续进行。参见下面的 IN_MOVE-SELF。
	IN_MOVE
	可以很便捷地对前面提到的两个移动事件(IN_MOVED_FROM | IN_MOVED_TO)进行逻辑操作的掩码。
	IN_CREATE
	在被监控目录中创建了子目录或文件。
	IN_DELETE
	被监控目录中有子目录或文件被删除。
	IN_DELETE_SELF
	被监控项目本身被删除。监控终止,并且将收到一个 IN_IGNORED 事件。
	IN_MOVE_SELF
	监控项目本身被移动。
	除了事件标志以外,还可以在 inotify 头文件(/usr/include/sys/inotify.h)中找到其他几个标志。例如,如果只想监控第一个事件,可以在增加监控时设置 IN_ONESHOT 标志。

下面就是Epoll+Inotify的实现

   

#include <stdio.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <unistd.h>  
#include <string.h>  
#include <stdlib.h>

/* 定义epoll最大监听的文件数量 */  
#define EPOLL_MAX_EVENTS    32

#define BUFFER_SIZE     1024
#define ARRAY_LENGTH    128     // 定义数组的长度  
#define NAME_LENGTH     128     // 定义文件名长度的限制 

struct file_name_fd_desc {  
    int fd;                         // 文件的描述符  
    char name[32];                  // 文件名  
    char base_name[NAME_LENGTH];    // 带绝对路径的文件名  
}; 


static struct epoll_event gEpollEventArray[EPOLL_MAX_EVENTS];

/* 定义一个数组用来存放对应文件的文件描述符和文件名 */  
static struct file_name_fd_desc gFileFdArray[ARRAY_LENGTH];

static int array_index = 0;
 
static char *base_dir;   
  

/*添加文件描述符到Epoll*/
static int add_to_epoll(int epoll_fd, int file_fd)
{
    int result;
    struct epoll_event eventItem;
    memset(&eventItem,0,sizeof(eventItem));
    eventItem.events=EPOLLIN;
    eventItem.data.fd = file_fd;
    result = epoll_ctl(epoll_fd,EPOLL_CTL_ADD,file_fd,&eventItem);   
    return result;
}

/*从Epoll删除文件描述符*/
static  void remove_epoll(int epoll_fd,int file_fd)
{
   epoll_ctl(epoll_fd,EPOLL_CTL_DEL,file_fd,NULL);
}

/*inotify监听到事件的处理逻辑,将新创建的文件添加到epoll,删除的文件从epoll删除*/
static int inotify_event_handler(int epoll_fd,int notify_fd)
{
    char InfoBuf[BUFFER_SIZE];
    struct inotify_event *event;
    char* p;
    int tmp_fd;
    int i;
  
    memset(InfoBuf,0,BUFFER_SIZE); 
    
    int result = read(notify_fd,InfoBuf,BUFFER_SIZE);
    for(p = InfoBuf ; p < InfoBuf + result;)
    {
       event = (struct inotify_event *)(p);
       if(event->mask & IN_CREATE)
       {
          sprintf(gFileFdArray[array_index].name,"%s",event->name);
          sprintf(gFileFdArray[array_index].base_name,"%s%s",base_dir,event->name);
          tmp_fd = open(gFileFdArray[array_index].base_name, O_RDWR);
          if(tmp_fd == -1)
          {
            printf("open file failure : %s\n",gFileFdArray[array_index].base_name);
            return -1;
          }
          gFileFdArray[array_index].fd = tmp_fd;
          add_to_epoll(epoll_fd,tmp_fd);
          array_index += 1;
          printf("add file to epoll %s\n",event->name);
       }else  //delete file
       {
          for(i = 0 ; i < ARRAY_LENGTH ; i++)
          { 
            if(!strcmp(gFileFdArray[i].name,event->name))
            {
               remove_epoll(epoll_fd,gFileFdArray[i].fd);
               gFileFdArray[i].fd = 0;
               memset(gFileFdArray[i].name, 0, sizeof(gFileFdArray[i].name));  
               memset(gFileFdArray[i].base_name, 0, sizeof(gFileFdArray[i].base_name));
               printf("delete file to epoll %s\n",event->name);
               break;  
            }
          }
       }

       p += sizeof(struct inotify_event) + event->len;    
    }
    
}



int main(int argc,char** argv)
{
   int mInotifyId;
   int mEpollId;

   char readbuf[1024];  
   int readlen;
   
   if(argc != 2)
   {
     printf("Paramter Error\n");
   }
   
   base_dir = argv[1];

   //epoll创建
   mEpollId = epoll_create(1);
   if(mEpollId == -1)
   {
      printf("Epoll Create Error\n");
      return -1;
   }    
   
   mInotifyId = inotify_init();

   //Observe Directory FILE_CREATE & FILE_DELETE
   //inotify添加对文件的监听
   int result = inotify_add_watch(mInotifyId,argv[1],IN_DELETE | IN_CREATE);
   if(result == -1)
   {
     printf("File Add Watch Failure\n");
     return -1;
   }
   
   add_to_epoll(mEpollId,mInotifyId);
   
   while(1)
   {
      result = epoll_wait(mEpollId,gEpollEventArray,EPOLL_MAX_EVENTS,-1);
      if(result == -1)
      {
         printf("epoll wait error\n");
         return -1;
      }
      else
      { 
         printf("file event happen\n");
         int i = 0; 
         for(i = 0; i < result; i++)
         {
            if(gEpollEventArray[i].data.fd == mInotifyId)
            {
                //inotify event handler
                if(-1 == inotify_event_handler(mEpollId,mInotifyId))  
                {  
                    printf("inotify handler error!\n");  
                    return -1;  
                }  
            
            }else
            {
                printf("read data.....\n");  
                //read content of file
                readlen = read(gEpollEventArray[i].data.fd, readbuf, 1024);  
                readbuf[readlen] = '\0';  
                printf("read data %s\n",readbuf);    
            }
           
         }

      }

    
    
   }

    


}
   
相关文章
相关标签/搜索