Linux inotify + Epoll实现机制
2018-01-05 15:49
309 查看
首先学习Inotify机制,就是Linux系统下对文件目录的监听,如果目录下有文件创建删除都可以被监听到,那这个有什么作用呢?
在Android Input系统中可以实现对设备热插拔的监听。我们先看一个简单的Demo
下面就是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);
}
}
}
}
}
在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);
}
}
}
}
}
相关文章推荐
- 源码剖析Linux epoll实现机制及Linux上惊群
- Linux select/poll和epoll实现机制对比
- Linux select/poll和epoll实现机制对比
- inotify + rsync实现linux文件实时同步,使用触发同步机制
- linux下epoll实现机制
- Linux下的多线程机制的分析与实现
- 【转】Linux内核进程调度以及定时器实现机制
- Linux 2.6.10内核下PCI Express Native热插拔框架的实现机制
- Linux 线程实现机制分析
- Linux下的动态连接库及其实现机制
- 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux内核抢占实现机制分析
- 用Linux 2.6内核中的文件系统变化通知机制inotify可实现跨机文件同步
- Linux 线程实现机制分析
- 【嵌入式Linux学习七步曲之第七篇 Linux的高级应用编程】Linux下的线程实现机制分析
- Linux-Netfilter&iptables实现机制的分析及应用
- Linux-千兆网卡驱动实现机制浅析
- Linux下的动态连接库及其实现机制
- Linux下的多线程机制的分析与实现
- Linux下的多线程机制的分析与实现
- [转贴]Linux 线程实现机制分析