您的位置:首页 > 其它

select和epoll实例详解

2017-01-12 20:53 127 查看


> select

select的作用是,让内核监听一个fd集合,当集合中的fd有事件时,select会返回有消息的fd子集。

/*
nfds 代表最大描述符加一
readfds 代表要读的文件描述符集合
writefds 代表可写的文件描述符集合
exceptfds 代表检测有异常的文件描述符集合
timeout 代表等待的时间,如果为NULL就一直等待
返回值:代表有事件文件描述符的个数
*/
int select(int nfds, fd_set *readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);

int main()
{
    int fd_mice = open("/dev/input/mice", O_RDONLY);
    int fd_keyb = open("/dev/input/event1", O_RDONLY);
    int readlen;
    char buf[1024];
    while(1)
    {
        // sigset_t
        // 集合
        fd_set set;
        FD_ZERO(&set); //清空集合
        FD_SET(fd_mice, &set);
        FD_SET(fd_keyb, &set);

        int nfds = fd_keyb + 1;

        struct timeval tv;
        tv.tv_sec = 2;
        tv.tv_usec = 0;

        // select是阻塞的函数,它的执行条件是,集合中有文件描述符有事件
        // 或者超时
        int ret = select(nfds, &set, NULL, NULL, &tv);
        // 返回值代表了select返回的有事件的文件描述符个数

        if(ret == -1)
        {
            // 出错
            if(errno == EINTR)     // 被信号打断
                continue;

            exit(1);
        }

        if(ret == 0)
        {
            printf("鼠标和键盘都没有动\n");
        }

        if(FD_ISSET(fd_mice, &set))
        {
            readlen = read(fd_mice, buf, sizeof(buf));
            printf("鼠标动了, readlen=%d\n", readlen);
        }

        if(FD_ISSET(fd_keyb, &set))
        {
            readlen = read(fd_keyb, buf, sizeof(buf));
            printf("键盘动了, readlen=%d\n", readlen);
        }

    }
}

> epoll

epoll的作用和select差不多,但是操作接口完全不同。

/*
epfd 相当于文件描述符集合
op 要做什么操作,EPOLL_CTL_ADD 增加描述符,BPOLL_CTL_MOD 修改描述符, BPOLL_CTL_DEL 删除描述符
fd 要操作的文件描述符

tyepdef union epoll_data{
     void *ptr;
     int fd;
     uint32_t u32;
     uint64_t u64;

}epoll_data_t;

//设置与要处理的事件相关的文件描述符
data.fd=listenfd;

struct epoll_event{
     uint32_t events;     // 表示要检查怎么操作,EPOLLIN可以读,EPOLLOUT可以写
     eopll_data_t data;     //设置与要处理的事件相关的文件描述符
}
*/
epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);

// 相当于select函数
/*
epfd 等待的是哪个集合
events 是一个epoll_event结构体数组  
maxevents 表示有events有多少个epoll_event结构体
timeout 超时,一毫秒为单位
*/
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);

int main()
<
4000
div>{
    int readlen;
    char buf[1024];
    int fd_mice = open("/dev/input/mice", O_RDONLY);
    if(fd_mice < 0)
    {
        perror("open mice");
        return 1;
    }
    int fd_keyb = open("/dev/input/event1", O_RDONLY);
    if(fd_keyb < 0)
    {
        perror("open keyboard");
        return 1;
    }

    // 相当于集合
    int epollfd = epoll_create(512);

    // 把fd_mice 和fd_keyb加入到epollfd中
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = fd_mice;
    int ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd_mice, &ev);
    if(ret < 0)
        perror("epoll_ctl mice");

    ev.events = EPOLLIN;
    ev.data.fd = fd_keyb;
    ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd_keyb, &ev);
    if(ret < 0)
        perror("epoll_ctl keyb");

    // select
    struct epoll_event out_events[2];
    while(1)
    {
          // 如果有事件来的时候就把ev的结构体拷贝到out_events里面去
        int ret = epoll_wait(epollfd, out_events, 2, 2000);
        printf("epoll_wait return %d\n", ret);
        if(ret < 0)
        {
            if(errno == EINTR)
            {
                continue;
            }
            else
            {
                perror("epoll_wait error\n");
                exit(1);
            }
        }
        if(ret == 0)
        {
            printf("nothing happened\n");
        }
        else // ret > 0
        {
            int i;
            for(i=0; i<ret; ++i)
            {
                struct epoll_event* p = &out_events[i];
                if(p->data.fd == fd_mice)
                {
                    readlen = read(fd_mice, buf, sizeof(buf));
                    printf("mouce event");
                }
                else if(p->data.fd == fd_keyb)
                {
                    readlen = read(fd_keyb, buf, sizeof(buf));
                    printf("keyboard event");
                }
            }
        }
    }
}

> select和epoll的区别

selectepoll
出现早
大规模文件描述符效率低大规模文件描述符效率高
小规模是select效率高使用红黑树来保存文件集合
使用位域来表示描述符集合
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  select epoll