基于视频压缩的实时监控系统-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;}
    }
}

 

posted @ 2020-08-04 14:25  打打打个大西瓜  阅读(211)  评论(0)    收藏  举报