Android系统--输入系统(二)必备Linux知识_实现inotify_epoll.c

课后作业

1. 编写 inotify_epoll.c, 用它来监测tmp/目录: 有文件被创建/删除, 有文件可读出数据

  • a. 当在tmp/下创建文件时, 会立刻监测到,并且使用epoll监测该文件

  • b. 当文件有数据时,读出数据

  • c. 当tmp/下文件被删除时,会立刻监测到,并且把它从epoll中移除不再监测

2. 程序基本框架

(1)初始化--初始化epoll和inotify,获取其fd

(2)添加事件

  • 对文件夹中文件的创建和删除进行检测--inotify_add_watch(mINotifyFd, dir, IN_DELETE | IN_CREATE);

  • 将监听事件加入epoll池中,监听事件行为--add_to_epoll(mINotifyFd, mEpollFd);

(3)等待事件发生

  • 添加、删除文件事件--read_process_inotify_fd(int mINotifyFd, int mEpollFd)

  • 往文件写入数据--read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN);

实现代码:

#include <sys/epoll.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <sys/inotify.h> #include <stdlib.h> #include <errno.h> #define DATA_MAX_LEN 512 #define MAX_FILES 1024 static char *base_dir; static char *epoll_files[MAX_FILES]; #if 0 typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t; #endif int add_to_epoll(int fd, int epollFd) { int result; struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.fd = fd; result = epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &eventItem); return result; } void rm_from_epoll(int fd, int epollFd) { epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, NULL); } /*函数说明:传入文件名,根据epoll_file数组指针,判断每一项指向的是否有内容,如有则比较文件名是否相同*/
int get_epoll_fd_for_name(char *name) { int i; char name_to_find[512]; sprintf(name_to_find, "%s/%s", base_dir, name); for (i = 0; i < MAX_FILES; i++) { if (!epoll_files[i]) continue; if (!strcmp(epoll_files[i], name_to_find)) return i; } return -1; } int read_process_inotify_fd(int mINotifyFd, int mEpollFd) { int res; char event_buf[512]; int event_size; int event_pos = 0; struct inotify_event *event; /* read */ res = read(mINotifyFd, event_buf, sizeof(event_buf)); if(res < (int)sizeof(*event)) { if(errno == EINTR) return 0; printf("could not get event, %s\n", strerror(errno)); return -1; } /* process * 读到的数据是1个或多个inotify_event * 它们的长度不一样 * 逐个处理 */ while(res >= (int)sizeof(*event)) { event = (struct inotify_event *)(event_buf + event_pos); //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); if(event->len) { if(event->mask & IN_CREATE) { printf("create file: %s\n", event->name); char *name = malloc(512); sprintf(name, "%s/%s", base_dir, event->name); int tmpFd = open(name, O_RDWR); //如有创建文件,则打开 printf("add to epoll: %s\n", name); add_to_epoll(tmpFd, mEpollFd); //将读取写入文件的事件加入epoll中 epoll_files[tmpFd] = name; //暂时保存文件名称,用于后面释放epoll中的该事件 } else { printf("delete file: %s\n", event->name); int tmpFd = get_epoll_fd_for_name(event->name); //利用文件名查找对应的事件fd if (tmpFd >= 0) { printf("remove from epoll: %s/%s\n", base_dir, event->name); rm_from_epoll(tmpFd, mEpollFd); free(epoll_files[tmpFd]); } } } event_size = sizeof(*event) + event->len; res -= event_size; event_pos += event_size; } return 0; } int main(int argc,char **argv) { int mEpollFd; int i; char buf[DATA_MAX_LEN]; int mINotifyFd; int result; // Maximum number of signalled FDs to handle at a time. static const int EPOLL_MAX_EVENTS = 16; // The array of pending epoll events and the index of the next event to be handled. struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS]; if(argc != 2){ printf("Usage: %s <tmp>\n",argv[0]); return -1; } base_dir = argv[1]; //1. init /* 1.1 epoll_create */ mEpollFd = epoll_create(8); /* 1.2 inotify_init */ mINotifyFd = inotify_init(); //2. add /* 2.1 add watch */ result = inotify_add_watch(mINotifyFd, base_dir, IN_DELETE | IN_CREATE); /* 2.2 addto epoll*/ add_to_epoll(mINotifyFd, mEpollFd); /* 3. epoll_wait */ while (1) { int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, -1); for (i = 0; i < pollResult; i++) { if (mPendingEventItems[i].data.fd == mINotifyFd) //事件fd为文件添加和删除,则跳转到inotify处理函数 { read_process_inotify_fd(mINotifyFd, mEpollFd); } else { printf("Reason: 0x%x\n", mPendingEventItems[i].events); int len = read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN); buf[len] = '\0'; printf("get data: %s\n", buf); } } } return 0;
}
具体操作:
  • gcc -o inotify_epoll inotify_epoll.c

  • mkdir tmp

  • ./inotify_epoll tmp/ &

  • mkfifo tmp/1 tmp/2 tmp/3

  • echo aaa > tmp/1

    echo bbb > tmp/2

    echo ccc > tmp/3

  • rm tmp/3

Android系统--输入系统(二)必备Linux知识_实现inotify_epoll.c的更多相关文章

  1. Android系统--输入系统(三)必备Linux知识_双向通信(scoketpair)

    Android系统--输入系统(三)必备Linux知识_双向通信(scoketpair) 引入 1. 进程和APP通信 创建进程 读取.分发 - 进程发送输入事件给APP 进程读取APP回应的事件 输 ...

  2. Android系统--输入系统(一)必备的Linux知识_inotify和epoll

    Android系统--输入系统(一)必备的Linux知识_inotify和epoll 引入 1. 笔记本电脑插入外接键盘,两个键盘都可以使用 a. 键盘即插即用--如何检测键盘的接入和拔出 hotpl ...

  3. Android系统--输入系统(十二)Dispatch线程_总体框架

    Android系统--输入系统(十二)Dispatch线程_总体框架 1. Dispatch线程框架 我们知道Dispatch线程是分发之意,那么便可以引入两个问题:1. 发什么;2. 发给谁.这两个 ...

  4. Android系统--输入系统(五)输入系统框架

    Android系统--输入系统(五)输入系统框架 1. Android设备使用场景: 假设一个Android平板,APP功能.系统功能(开机关机.调节音量).外接设备功能(键盘.触摸屏.USB外接键盘 ...

  5. Android系统--输入系统(六)模拟输入驱动程序

    Android系统--输入系统(六)模拟输入驱动程序 1. 回顾输入子系统 简单字符设备驱动:应用程序通过调用驱动所实现的函数使能硬件. 输入子系统:由于有多个应用程序使用输入子系统,故肯定使用的是早 ...

  6. Android系统--输入系统(九)Reader线程_核心类及配置文件

    Android系统--输入系统(九)Reader线程_核心类及配置文件 1. Reader线程核心类--EventHub 1.1 Reader线程核心结构体 实例化对象:mEventHub--表示多个 ...

  7. Android系统--输入系统(十)Reader线程_核心类及配置文件深入分析

    Android系统--输入系统(十)Reader线程_核心类及配置文件深入分析 0. 前言 个人认为该知识点阅读Android源代码会不仅容易走进死胡同,并且效果并不好,前脚看完后脚忘记,故进行总结, ...

  8. Android系统--输入系统(七)Reader_Dispatcher线程启动分析

    Android系统--输入系统(七)Reader_Dispatcher线程启动分析 1. Reader/Dispatcher的引入 对于输入系统来说,将会创建两个线程: Reader线程(读取事件) ...

  9. Android系统--输入系统(八)Reader线程_使用EventHub读取事件

    Android系统--输入系统(八)Reader线程_使用EventHub读取事件 1. Reader线程工作流程 获得事件 size_t count = mEventHub->getEvent ...

随机推荐

  1. Javascript间歇调用和超时调用

    间歇调用:每隔指定的时间就执行一次代码 超时调用:在指定的时间过后执行代码  HTML Code  12345678910111213141516171819   <!DOCTYPE html& ...

  2. try finally 执行顺序

    class Exc{ int a; int b; } public class Except { @SuppressWarnings("finally") static int c ...

  3. cocos2dx - 部署到android真机上错误整理

    利用Cgywin编译工具来将cocos2dx 在Android运行所需要的C++文件编译 1. ./build_native.sh(最后一把执行出错) please define NDK_ROOT i ...

  4. Android开发:《Gradle Recipes for Android》阅读笔记1.2

    在android开发中会需要配置使用app的android SDK的最低版本和目标版本,这个是bulidl.gradle的android模块设置.默认有以下几个设置: applicationId,这个 ...

  5. Android开发:《Gradle Recipes for Android》阅读笔记1.1

    第一章1.1节 注:下面都是用android studio新建出来的默认项目配置,没有修改 1.settings.gradle记录了哪些子目录包含了它们自己的工程,例如:include':app',如 ...

  6. [转]JavaWeb之 Servlet执行过程 与 生命周期

    https://www.cnblogs.com/vmax-tam/p/4122105.html Servlet的概念 什么是Servlet呢? Java中有一个叫Servlet的接口,如果一个普通的类 ...

  7. 【BZOJ2226】[Spoj 5971] LCMSum 莫比乌斯反演(欧拉函数?)

    [BZOJ2226][Spoj 5971] LCMSum Description Given n, calculate the sum LCM(1,n) + LCM(2,n) + .. + LCM(n ...

  8. Android获取应用程序的信息

    1.获取应用程序的版本号: private String getAppVersionName() { String versionName = ""; try { PackageM ...

  9. Java 自带的加密类MessageDigest类(加密MD5和SHA)

    Java 自带的加密类MessageDigest类(加密MD5和SHA) - X-rapido的专栏 - CSDN博客 https://blog.csdn.net/xiaokui_wingfly/ar ...

  10. 段合并 segments merge 被删除的文档的删除时间

    2.5 段合并 每个索引分为多个“写一次,读多次”的段 write once and read many times  segments 建立索引时,一个段写入磁盘以后就不能更新:被删除的文档的信息存 ...