select poll epoll 浅析
reference:
http://blog.csdn.net/jiange_zh/article/details/50811553
1, 三者可以对多个文件描述符进行监听,当ready后可以进行预期的IO操作;
2, select可以处理的event是read/write ready,poll可以处理更加复杂的event POLLIN/POLLOUT(相对于select的readfds,writefds ready)/POLLPRI/POLLRDHUP/POLLERR/POLLHUP/POLLNVAL, epoll在poll的基础上,增加了EPOLLET (edge trigger 边沿触发)和EPOLLONESHOT;
3, select/poll比epoll的效率低,随着fd数量的增加,对比越明显。select/poll每一次poll都会在kernel space遍历所有的文件描述符,epoll是在设备ready(粗略理解成fd ready)后通过回调函数将此fd放到就绪链表中,每次poll将此链表返回;
epoll的优势:
1, 在大型服务器上,数以千计的fd需要快速响应,epoll的时间复杂度比select/poll高出数量级,空间复杂度的影响可以忽略;
2, epoll可以通过epoll_ctl函数动态添加/修改/删除,对于不能预期的fd,比较容易添加到poll队列中;(select和poll也可以通过编程手段实现这一点,但自身支持会简化使用场景)
select:
#include <stdio.h> #include <string.h> #include <sys/select.h> int main(void) { int maxfd = 0; int ret = -1; fd_set rfds; struct timeval tv; char buf[1024] = {0x0}; printf("select testing.\n"); while(1) { FD_ZERO(&rfds); FD_SET(0, &rfds); maxfd = 1; /* maxfd = fd + 1*/ tv.tv_sec = 0; tv.tv_usec = 100*1000; /* 100ms. */ ret = select(maxfd, &rfds, NULL, NULL, &tv); if (ret == 0x0) { //printf("time out.\n"); continue; } else if (ret < 0x0) { perror("select:"); continue; } else { if(FD_ISSET(0, &rfds)) { memset(buf, 0x0, sizeof(buf)); ret = read(0, buf, sizeof(buf)); if(0x0 == strncmp(buf, "quit", 4)) return 0x0; printf("buf:%s", buf); } } } return 0x0; }
poll:
#include <stdio.h> #include <poll.h> #include <errno.h> #include <string.h> int main(void) { struct pollfd pfd; int ret = -1; char buf[1024] = {0x0}; printf("poll testing.\n"); memset(&pfd, 0x0, sizeof(pfd)); pfd.fd = 0; pfd.events = POLLIN; while(1) { ret = poll(&pfd, 1, 100); if(ret == -1 && errno == EINTR) continue; if(ret < 0) perror("poll:"); if(ret == 0x0) { //printf("time out!\n"); continue; } if(pfd.revents & POLLIN) { ret = read(pfd.fd, buf, sizeof(buf)); printf("buf:%s"); if(0x0 == strncmp("quit", buf, 4)) return 0x0; } } return 0x0; }
epoll:
#include <stdio.h> #include <string.h> #include <sys/epoll.h> #define MAX_EVENTS (10) int main(void) { int epfd = -1; int ret = -1; int fd = -1; int i = 0; struct epoll_event ev; struct epoll_event revs[MAX_EVENTS]; char buf[1024] = {0x0}; printf("epoll testing\n"); epfd = epoll_create(1); if(epfd < 0x0) { perror("epoll_create:"); return -1; } memset(&ev, 0x0, sizeof(ev)); ev.data.fd = 0; ev.events = EPOLLIN; epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &ev); while(1) { memset(&revs, 0x0, sizeof(revs)); ret = epoll_wait(epfd, &revs[0], MAX_EVENTS, 10); switch(ret) { case 0: { //printf("time out!\n"); break; } case -1: { perror("epoll_wait:"); break; } default: { for(i = 0; i < ret; i++) { fd = revs[i].data.fd; if(revs[i].events & EPOLLIN) { memset(buf, 0x0, sizeof(buf)); ret = read(fd, buf, sizeof(buf)); if(0x0 == strncmp(buf, "quit", 4)) return 0x0; printf("buf:%s", buf); } } } } } return 0x0; }