嵌入式-项目1-基于视频压缩的实时监控系统-2.基于Epoll的采集端程序框架设计

第2课-基于Epoll的采集端程序框架设计

epoll的使用流程

(1)创建

(2)加入事件

(3)等待和处理

 

 

步骤:

  1. 创建源文件

我们的软件体系到底能不能完成,关键的事情就是加入事件(摄像头)。

这里我们区分,主程序是第一个模块,摄像头采集系统是第二个模块,传输系统是第三个模块,配置子系统是第四个模块。每个模块对应一个原文件,我们要创建四个原文件。分别为:main.c cam.c net.c cfg.c

 

 

  1. 模型代码化

我们创建一个include文件,用来存放我们要用到的头文件。创建头文件main.h。在这里建立结构体struct server,在cam.c中建立结构体struct cam,在net.c中建立struct tcp,在cfg.c中建立struct cfg,具体内容先不去填写。今天我们的任务就是将main.h中的内容进行完善即可。

主程序对应着与配置子系统、采集子系统、传输子系统和epoll框架这四个内容的关系。我们就建立四个成员对应这四个关系。我们可以进行函数下放,就要下放接口。子程序同时也提供函数接口,这样就完成了函数的下放。我们看看有哪些接口:

(1)添加事件到EPOLL

(2)EPOLL中删除事件

现在我们在想为什么不直接用系统带的函数epoll_ctl,还要自己写呢?因为我们用的epoll_ctl是依赖于struct epoll_event结构来的,但是这个结果里面的信息有限:

typedef union epoll_data

{

void *ptr;

int fd;

uint32_t u32;

uint64_4 u64;

}epoll_data_t;

stryct epoll_event

{

unint32_t events;   /*Epoll events*/

epoll_data_t data;  /*User data variable*/

};

也就只有一个文件类型和一个联合(包含4项),我们要是想多保存点信息就不行了。我们可以使这个指针再加一些附加结构,这里面保存我们想要有的其他信息。我们在main函数中定义就可以。

 

struct server

{

int epfd;   //指向epoll

struct cam *cam;  //指向采集子系统

struct tcp_srv *srv; //指向传输子系统

struct cfg* cfg;   //指向配置子系统

};

  1. 程序

main.c

#include<stdio.h>

#include<unistd.h>

#include<fcntl.h>

#include<sys/epoll.h>

#include<main.h>

#include<stdbool.h>

struct event_ext    //我们的附加的结构体,用来补充epoll_ctl函数

{

int fd;

bool epolled;   //表示我们的时间是否已经加入到了我们监控池之中

uint32_t events;  //事件的类型

void (*handler)(int fd,void *arg);  //函数指针,其中有两个成员

void *arg;  //提供给handler使用的指针

};

/*由于我们附加的函数的作用,我们还得需要自己手写我们对人epoll事件的添加和删除函数*/

/*基于新的结构体而定创造函数,结构体中有的内容,这里面都该有,第一个结构*/

struct event_ext *epoll_event_creat(int fd,uint32_t type,void (*handler)(void *arg),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;

};

//添加epoll,第二个结构

int epoll_add_event(int epfd, struct event_ext *ev)   

 /*创建一个事件附加结构,并将参数传进来*/

{

struct epoll_event epv; //先创建一个结构体

int op; //定义原本的epoll_ctl中的第二个参数

//2. 初始化epoll_event(将附加结构挂载到epoll_event中)

epv.data.ptr = ev;   //将附加的结构挂载原来系统带的结构体上

epv.events =  ev->events;  //初始化数据类型,原本的epoll_event中就这两个成员

if(ev->epolled)  //文件已经存在的时候,就是进行修改,否则进行加入

{

op = EPOLL_CTL_MOD; //修改的操作

}

else

{

op = EPOLL_CTL_ADD;//添加的操作

ev->epolled = true; //第一次添加进去之后,标识就变成了真

}

//3. 将epoll_even加入到epoll中

epoll_ctl(epfd,op,ev->fd,&epv);

return 0;

};

//从epoll池中删除

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));  //为结构体分配空间

//1. 创建epoll

srv_main->epfd = epoll_create(512);

//2. 加入等事件,将这个程序进行下放-交给子系统,这之后就要设置子系统的函数接口

srv_main->cam = cam_sys_init();

srv_main->srv = net_sys_init();

//3. 等待事件发生且处理

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里面的内容类型与event里面的一致*/

{

//处理

e->handler(e->fd,e->arg);

}

if((event&EPOLLOUT)&&(e->events&EPOLLOUT)) /*若是读的事件,附加条件要e里面的内容类型与event里面的一致*/

{

//处理

e->handler(e->fd,e->arg);

}

if((event&EPOLLERR)&&(e->events&EPOLLERR))  /*若是读的事件,附加条件要e里面的内容类型与event里面的一致*/

{

//处理

e->handler(e->fd,e->arg);

}

}

}

return -1;   //按道理来讲我们而定循环是不应该结束的,要是结束了就说明程序出错了

}

cam.c

#include<main.h>

 

 

struct cam

{

 

};

 

struct cam *cam_sys_init()

{

//1. 初始化采集子系统

 

 

//2. 将采集子系统中的事件加入epoll池

 

 

return NULL;

};

 

net.c

#include<main.h>

 

struct tcp_srv

{

 

};

 

struct tcp_srv *net_sys_init()

{

//1. 初始化传输子系统

 

 

//2. 将传输子系统中的事件加入epoll池

 

 

return NULL;

 

 

};

cfg.c

struct cfg

{

 

};

 

 

 

  1. 编译

创建一个Makefile文件,touch Makefile。通过samb服务器打开这个文件我们写下如下的文件:

BIN = wcamsrv                                                          //输出的文件名字

INC = -Iinclude/     /*表示需要引用的是当前文件下的include文 件,-I表示的对应的操作*/

SRC = $(wildcard *.c)                         //表示寻找的该路径下的所有.c文件,都给SRC

OBJ = $(patsubst %.c, %.o, $(SRC) )     /*表示输出的格式是.o的形式的,对应的三个参数,第一个参数表示所有的.c文件,第二个参数表示输出都是.o文件,第三个参数表示来自SCR变量*/

CC = arm-linux-gcc                                                   //表示编译器的选择

CFLAGS = $(INC) -g                                                           //编译选项

$(BIN):$(OBJS)                                                               //编译依赖

$(CC) -o $@ $^                                                          //编译输出

clean:                                                                      //清除选项

rm $(OBJS) $(BIN)                                                        

 

猜你喜欢

转载自www.cnblogs.com/free-1122/p/9709830.html