您的位置:首页 > 运维架构 > Linux

Linux inotify + Epoll实现机制

2018-01-05 15:49 309 查看
  首先学习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);
}

}

}

}

}   

 

   
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: