基于视频压缩的实时监控系统-sprint1基于epoll架构的采集端程序设计
part1:产品功能

part2:epoll机制

select与epoll区别
1、select与epoll没有太大的区别。除了select有文件描述符限制(1024个),select每次调用都需要将
fd集合拷贝到内核,且监听过程遍历所有的文件位置,开销很大。
2、epoll监测无上限,在注册新事件是就会一次性把所有fd拷贝到内核,无需遍历即可查询到监听的位
置,提高监听效率。
(epoll是Linux中最优秀的多路复用机制)
epoll的优势:1、多路复用;2、阻塞IO;3、无需遍历所有文件即可知道错误的文件位置(高效)
4、监控文件无上限
epoll支持管道、FIFO、套接字、POSIX 消息队列、终端等,但不支持普通文件(文本文件,可执行性文件)
| 创建epoll监听池 | epfd = epoll_create(50) 返回epfd指向创建的监听池 |
| 添加epoll监听事件 |
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event) 监听池epfd 操作符 要监听文件的fd 监听结构类型 |
| 等待监听事件发生 | n = epoll_wait(epfd, events, 100, -1) 返回事件发生个数 |
eg:使用epoll监听两个管道的通信
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/epoll.h> int main() { int fd1, fd2; int efd; int i,n; char c; struct epoll_event event; struct epoll_event* events; //创建管道FIFO mkfifo("/tmp/fifo1", 0666); mkfifo("/tmp/fifo2", 0666); fd1 = open("/tmp/fifo1", O_RDONLY); fd2 = open("/tmp/fifo2", O_RDONLY); //1、创建epoll监听池 efd=epoll_create1(0); //2、构建监听事件,加入监听池 event.events = EPOLLIN | EPOLLET; //可读 边沿触发 event.data.fd = fd1; //关注的文件 epoll_ctl(efd, EPOLL_CTL_ADD, fd1, &event); event.events = EPOLLIN | EPOLLET; //可读 边沿触发 event.data.fd = fd2; //关注的文件 epoll_ctl(efd, EPOLL_CTL_ADD, fd2, &event); //3、等待事件的发生,监听 events = calloc(100, sizeof event); //保存事件数组 n = epoll_wait(efd, events, 100, -1); for (i = 0; i < n; i++) { if (events[i].events & EPOLLIN) { //处理 read(events[i].data.fd, &c, 1); printf("file %d can be read\n", events[i].data.fd); } if (events[i].events & EPOLLOUT) {/*处理*/} if (events[i].events & EPOLLERR) {/*处理*/} } free(events);close(fd1);close(fd2); //关闭打开的文件+释放申请的堆内存 }
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int main() { int fd; char c = 'c'; fd = open("/tmp/fifo1", O_WRONLY); write(fd, &c, 1); close(fd); return 0; } #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/epoll.h> int main() { int fd; char c = 'c'; fd = open("/tmp/fifo2", O_WRONLY); write(fd, &c, 1); close(fd); return 0; }
检测:分别编写程序向两个管道文件内写入数据,编译运行后epoll立即检测到事件发生

part3:基于epoll采集端程序设计
epoll架构加入摄像头采集端,监听摄像头是否采集到数据(事件)
int main() { struct wcamsrv* ws; ws = calloc(1, sizeof(struct wcamsrv)); //1、创建epoll ws->app = app_poll_create(0); //2、加入事件 ws->cfg = cfg_init(); //配置子子函数 ws->cap = cap_init(); //捕获(采集) ws->tran = transfer_init();//传输子系统 //3、等待事件 return app_exec(ws->app); }
void app_add_event(app_poll_t app, app_event_t app_e) { //事件监听模式选择 int op; struct epoll_event event; event.data.ptr = app_e; event.events = app_e->events; if (app_e->epolled) { op = EPOLL_CTL_MOD;//修改 } else { op = EPOLL_CTL_ADD;//增加 app_e->epolled = true; } epoll_ctl(app->epfd, op, app_e->fd, &event); } app_poll_t app_poll_create(int event_max) { //初始化函数 app_poll_t app; app = calloc(1, sizeof(struct app_poll)); if (event_max > 0) app->event_max = event_max; else app->event_max = DEF_MAX; app->epfd = epoll_create(app->event_max); if (app->epfd < 0) { perror("epoll create"); goto err_mem; } return app; err_mem: free(app); return NULL; } void app_exec(app_poll_t app) { int i; int fds; int event; app_event_t app_e; struct epoll_event events[app->event_max];//事件数组 while (1) { fds = epoll_wait(app->epfd, events, app->event_max, 1000); for (i = 0; i < fds; i++) { app_e = (app_event_t)events[i].data.ptr; event = events[i].events; if (event & EPOLLIN) app_e->handler_rd(app_e->fd, app_e->arg_rd);//处理 if (event & EPOLLOUT) app_e->handler_wr(app_e->fd, app_e->arg_wr);//处理 if (event & EPOLLERR) app_e->handler_er(app_e->fd, app_e->arg_er); } } } void app_event_add_handler(app_event_t app_e, enum app_op type, void (*handler)(int, void*), void* arg) { //事件处理函数 switch (type) { case NOTIFIER_READ:{ app_e->events = EPOLLIN; app_e->handler_rd = handler; app_e->arg_rd = arg; break;} case NOTIFIER_WRITE:{ app_e->events = EPOLLOUT; app_e->handler_rd = handler; app_e->arg_rd = arg; break;} case NOTIFIER_ERROR:{ app_e->events = EPOLLERR; app_e->handler_rd = handler; app_e->arg_rd = arg; break;} } }

浙公网安备 33010602011771号