一、select()
select的大致用法:
fd_set fd_read, fd_write; struct timeval tv; FD_ZERO(&fd_read); FD_ZERO(&fd_write); FD_SET(sock1,&fd_read); FD_SET(sock2,&fd_write); int largest_sock = sock1 > sock2?sock1:sock2; tv.tv_sec = 10; tv.tv_usec = 0; int ret = select(largest_sock, &fd_read,&fd_write,NULL,&tv); if( ret == -1) // ... else if (ret == 0) // ... else { if( FD_ISSET(sock1,&fd_read); // ... if( FD_ISSET(sock2,&fd_write); // ... }
select的缺点:
1.select会修改传递的fd_set,所以每次调用完select后,fd_set将不可再复用
2.select调用结束后,为了找出就绪的文件描述符,必须要用FD_ISSET去测试遍历整个fd_set
3.select支持的文件描述符有限,在linux下这个数字为1024,但可以被修改
4.当一个线程调用select()阻塞时,不能从其他线程修改fd_set.
5.必须通过监视文件描述符的读就绪条件,才能检测到对端关闭
二、poll()
poll()的大致用法:
struct pollfd fds[2]; fds[0].fd = sock1; fds[0].events = POLLIN; fds[1].fd = sock2; fds[1].events = POLLOUT; int ret = poll(&fds,2,10000); if( ret == -1) // ... else if( ret == 0) // ... else { if( fds[0].revents & POLLIN) { fds[0].revent = 0; // ... } if( fds[1].revents & POLLIN) { fds[1].revent = 0; // ... } }
poll()的优点:
1.没有文件描述符的数量限制
2.可以复用epollfd数组
3.可以不监视文件描述符的读就绪条件,也能发现对端socket关闭
poll()的缺点:
1.像select,需要遍历来发现就绪文件描述符
2.像select,无法在being polled的时候修改epollfd
3. epoll()
epoll()的大致 int epollfd = epoll_create1(0); struct epoll_event ev = {0}; ev.data.ptr = pConnection1; ev.events = EPOLLIN | EPOLLLONESHOT epoll_ctl( epollfd, EPOLL_CTL_ADD,pConnection1->getConnection(),&ev);
struct epoll_event pevents[20]; int ready = epoll_wait(epollfd,pevents,20,10000); if( ready == -1) // ... else if( ready == 0) // .... else { for(int i =0;i<ready;i++) { // ... }
}
epoll的优点:
1.epoll只返回就绪事件的文件描述符集合
2.epoll允许将其他内容附加到event而不仅是文件描述符
3.可以在任何时间添加、删除、修改event,即使线程正在调用event_wait
4.可以允许有多个线程同时在一个epoll list中调用epoll_wait()。