Linux-视频监控系统(2)-Epoll的介绍及使用

xiaoxiao2021-02-28  74

1、什么是Epoll

1.1阻塞型IO和多路复用

假如说现在有一个进程需要对设备进行读写,但是这个过程一般需要时间不能马上完成,为了节约CPU资源,这时候一般进程都采取阻塞的方法,把自己挂起,等有设备已经完成操作了再自行其他程序。这种等待方法叫做阻塞型IO 假如一个进程需要同时对4个设备文件进行监控,比如说需要监控打印机有没有打印完成、键盘有没有输入数据,这个过程就叫做多路复用。 那么哪个函数可以既可以实现阻塞型IO又可以实现多路复用呢? select函数,下面是select函数的使用复习 1、初始化需要操作的文件集合FD_ZERO(&set) 2、把文件描述符一个一个的加到集合中,FD_SET 3、调用select,开始监控,如果没有文件符合会阻塞在这里,直到超时或者有文件满足要求,然后继续运行 4、遍历每个文件,找到哪个文件发生了变化 那么select存在哪些缺点呢?在最后遍历文件的过程中,是极其耗费时间的过程如果文件太多,那这对资源更是一个极大的浪费。  

所以这里引入Epoll函数,它同样可以实现阻塞和多路复用,同时不需要遍历所有文件就可以知道是哪个文件发生了什么变化,比如说文件里面已经有数据了可以唤醒应用程序来读,比如说应用程序要求写入的数据已经写入了,可以继续做下面的事情了。。而且Epoll可以监控的文件是没有上限的!

 

 

2、怎么使用Epoll

但是要注意Epoll支持管道,FIFO,套接字,POSIX消息队列,终端,设备等,但就是不支持普通文件!!!比如说文件文件,MP3文件等普通文件它都不支持。 Epoll的使用分为3个环节。 epoll_create/epoll_create1 (创建epoll监听池) epoll_ctl (添加要监听的事件) epoll_wait (等待事件的发生)  

epoll_create

在Linux下man一下这个函数: epoll_create是创建一个监听池,在2.8之前的内核版本中它表明监听文件的数量,在2.8以后的版本中没有任何意义。 epoll_create1有一个flags的参数,当参数为0时和epoll_create函数是一样的同时这个函数的返回值就是监听池的描述符。  

epoll_ctl

 

添加要监听的事件,比如说添加A文件可读、添加A文件可写,当事件发生时可以立马知道是哪个事件发生了什么操作,所以不再需要遍历所有文件了。 它的原型是: int epoll_ctl(int enfd, int op, int fd, struct epoll event *event) 第一个参数是监听池的fd,第二个参数是操作的类型比如加入事件、取出事件、删除事件、修改事件等,第三个是事件所对应文件的fd,第四个是事件类型, struct epoll_event { __uint32_t events epoll data data; }; 第一个是事件的类型比如读写,EPOLLIN、EPOLLOUT。 返回值是int类型,成功返回0,失败返回-1  

epoll_wait 

 

等待事件的发生,它的原型是 int epoll_wait (int epfd, struct epoll_event *events,                 int maxevent,int timeout) 第一个参数是epfd,第二个参数存放发生事件的指针,当事件发生后会把对应文件的操作事件写入这个数组。第四个是最大事件的数组,第五个是超时时间。 那么在摄像头监控系统中存在哪些需要等待的事情呢? 1、摄像头存在一帧新的图像(可读) 2、socket可以发送数据(可写) 3、socket可以接收数据(可读) 因此在我们的监控系统中非常有必要引入Epoll框架程序

 

下面写一个简单的程序来使用Epoll:

 

#include<stdio.h> #include<stdlib.h> #include<fcntl.h> #include<sys/epoll.h> int main() { int fd1,fd2; int ep_fd; struct epoll_event event; struct epoll_event *events; int n,i; char c; mkfifo("/tmp/fifo1",0666); mkfifo("/tmp/fifo2",0666); fd1 = open("/tmp/fifo1",O_RDONLY); fd2 = open("/tmp/fifo2",O_RDONLY); ep_fd = epoll_create1(0); event.events = EPOLLIN | EPOLLET; event.data.fd = fd1; epoll_ctl(ep_fd, EPOLL_CTL_ADD, fd1, &event); event.events = EPOLLIN | EPOLLET; event.data.fd = fd2; epoll_ctl(ep_fd, EPOLL_CTL_ADD, fd2, &event); events = calloc(100, sizeof(event)); n = epoll_wait(ep_fd, events, 100, -1); for(i=0; i<n; i++) { if(events[i].events & EPOLLIN) { read(events[i].data.fd, &c, 1); printf("file %d read %c!\n",events[i].data.fd,c); } if(events[i].events & EPOLLOUT) { } } close(fd1); close(fd2); close(ep_fd); return 0; }

 

 

然后编写一个fifo读写的程序:

 

#include<stdio.h> #include<stdlib.h> #include<fcntl.h> #include<sys/epoll.h> int main() { int fd; char c = 'x'; fd = open("/tmp/fifo1", O_WRONLY); write(fd, &c, 1); close(fd); return 0; }

同样写出对另一个fifo2文件的读写程序。

 

然后编译后依次运行这几个文件,如果写入数据后ep文件打印出对于的字符即编写成功。

 

更多Linux资料及视频教程点击这里

转载请注明原文地址: https://www.6miu.com/read-69032.html

最新回复(0)