> 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()
{
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的区别
select | epoll |
---|---|
出现早 | 晚 |
大规模文件描述符效率低 | 大规模文件描述符效率高 |
小规模是select效率高 | 使用红黑树来保存文件集合 |
使用位域来表示描述符集合 |