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

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

2017-07-11 15:48 507 查看

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文件打印出对于的字符即编写成功。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mini2440 linux Epoll