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

采集端分为以下几个子系统:
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行是编译和清除的命令。
 

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

 

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值