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

Linux-视频监控系统(3)-Epoll框架的实现

2017-07-11 22:07 696 查看
采集端分为以下几个子系统:

1、采集端子系统

2、存储子系统

3、压缩子系统

4、传输子系统

5、配置子系统
6、主程序

首先对整体的程序框架做一个划分,对于每个子系统都建立一个.c文件,同时对每个子系统都建立一个结构体来描述,然后把所有需要用到的头文件都放到include文件夹中。

然后提炼出哪些事件是需要等待的,可以把这些事件加入Epoll池中,分析如下:

1、摄像头可读(摄像头的设备文件已经有了一帧图像)

2、socket可写(可以通过socket发送数据了)

3、存储设备可写(可以往SD卡中存放数据)

可能分析的不够全面,会把有些事件漏掉,想起了以后再加好了。

对于Epoll的事件结构是这样的:struct epoll_event{
__uint32_t events;
epoll_data_t data;
};如果需要保存一些信息,比如说设备文件fd,对应的处理函数和其他标志位,就是采用data里面的结构来保存的:
typedef union epoll_data{
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
};由于结构里的数据只可以用一个,因此为了方便起见,我们自己定义一个结构来保存设备文件fd、一些标志位和处理函数,并把这个结构的指针挂接早ptr指针中:
struct event_ext
{
int fd;//监控文件的fd
bool epolled;//事件是否在池中的标志
uint32_t events;//事件类型
void (*handler)(int fd, void *arg);//处理函数
void *arg;//处理函数的参数
};

这个结构定义在main.c中,然后在main.h中定义:
struct server
{
int epfd;//指向创建的Epoll
struct cam *cam;//指向摄像头子系统
struct tcp_srv *tcp_srv;//指向网络子系统
struct cfg *cfg;//指向配置子系统
};
struct server *srv_main;

在cam.c中定义:
struct cam
{

};

struct cam *cam_sys_init()
{
//初始化采集子系统

//将采集子系统中的事件加入Epoll池

return NULL;
}在net.c中定义:
struct tcp_srv
{

};

struct tcp_srv *net_sys_init()
{
//初始化传输子系统

//将传输子系统的事件加入Epoll池
}在配置文件中定义:
struct cfg
{

};


定义好每个子系统的结构后开始设计主程序的框架,在主程序中主要实现Epoll的初始化,各个子模块的初始化,然后添加事件,最后等待事件的发生,具体事件的处理交给各个子系统。同时为了使整个框架更灵活,把Epoll事件的添加交给子系统完成,具体需要添加/修改哪个事件有子系统觉得,同时事件的添加放在子系统初始化中完成。然后给子系统提供事件初始化函数、事件添加/修改、事件删除的接口。最后main.c文件如下:
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <fcntl.h>
#include <sys/epoll.h>

#include "main.h"

struct event_ext
{
int fd;//监控文件的fd
bool epolled;//事件是否在池中的标志
uint32_t events;//事件类型
void (*handler)(int fd, void *arg);//处理函数
void *arg;//处理函数的参数
};

//初始化事件的接口
struct event_ext *epoll_event_create(int fd, uint32_t type, void (*handler)(int , void *), void *arg)
{
struct event_ext *e = calloc(1,sizeof(struct event_ext));

e->fd = fd;
e->events = type;
e->handler = handler;
e->arg = arg;

return e;
}

//添加事件的接口
int epoll_add_event(int epfd, struct event_ext *ev)
{
struct epoll_event epv;
int op;

//初始化epoll_event
epv.data.ptr = ev;
epv.events = ev->events;

if(ev->epolled)
{
op = EPOLL_CTL_MOD;
}
else
{
op = EPOLL_CTL_ADD;
ev->epolled = true;
}

//将epoll_event加入epoll
epoll_ctl(epfd, op, ev->fd, &epv);

return 0;
}

//删除事件
int epoll_del_event(int epfd, struct event_ext *ev)
{
epoll_ctl(epfd, EPOLL_CTL_DEL, ev->fd, NULL);
ev->epolled = false;

return 0;
}

int main()
{
struct epoll_event events[512];
int fds;
int i;
uint32_t event;
struct event_ext *e;

srv_main = calloc(1,sizeof(struct server));

//创建Epoll
srv_main->epfd = epoll_create(512);

//子系统初始化
srv_main->cam = cam_sys_init();
srv_main->tcp_srv = net_sys_init();

//等待事件发生并处理
while(1)
{
fds = epoll_wait(srv_main->epfd, events, 512, 1000);
for(i=0; i<fds; i++)
{
event = events[i].events;
e = events[i].data.ptr;

if((event & EPOLLIN) && (e->events & EPOLLIN))
{
e->handler(e->fd, e->arg);
}
if((event & EPOLLOUT) && (e->events & EPOLLOUT))
{
e->handler(e->fd, e->arg);
}
if((event & EPOLLERR) && (e->events & EPOLLERR))
{
e->handler(e->fd, e->arg);
}
}
}

return -1;
}

然后是Makefile的编写:

BIN = wcamsrv
INC = -Iinclude/
SRC = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRC))

CC = arm-linux-gcc
CFLAGS = $(INC) -g

$(BIN):$(OBJS)
$(CC) -o $@ $^

clean:
rm $(OBJS) $(BIN)BIN一个变量,保存目标的二进制文件
INC是头文件的路径,包含include下的所有文件

SRC是需要编译的源文件,使用wildcard函数来寻找所有的.c文件

OBJS保存生成的.o文件

CC是编译工具,它是arm-linux-gcc

下面2行是编译和清除的命令。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mini2440 Epoll linux