1. select
1.select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开 的文件描述符个数并不能改变select监听文件个数
2.解决1024以下客户端时使用select是很合适的,但如果链接客户端过多,select采用 的是轮询模型,会大大降低服务器响应效率,不应在select上投入更多精力
#include <sys/select.h> /* According to earlier standards */ #include <sys/time.h> #include <sys/types.h> #include <unistd.h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); void FD_CLR(int fd, fd_set *set); 把文件描述符集合里fd清0
- nfds: 监控的文件描述符集里最大文件描述符加1,因为此参数会告诉内核检测前多少个文件描述符的状态
- readfds:监控有读数据到达文件描述符集合,传入传出参数
- writefds:监控写数据到达文件描述符集合,传入传出参数
- exceptfds:监控异常发生达文件描述符集合,如带外数据到达异常,传入传出参数
- timeout:定时阻塞监控时间,3种情况
- NULL,永远等下去
- 设置timeval,等待固定时间
- 设置timeval里时间均为0,检查描述字后立即返回,轮询
struct timeval { long tv_sec;/* seconds */ long tv_usec;/*microseconds */ }; int FD_ISSET(int fd, fd_set *set); void FD_SET(int fd, fd_set *set); void FD_ZERO(fd_set *set); 测试文件描述符集合里fd是否置1 把文件描述符集合里fd位置1 把文件描述符集合里所有位清0
2. poll
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); struct pollfd { int fd; /* 文件描述符 */ short events; /* 监控的事件 */ short revents;/* 监控事件中满足条件返回的事件 */ };
- POLLIN普通或带外优先数据可读,即POLLRDNORM | POLLRDBAND
- POLLRDNORM-数据可读
- POLLRDBAND-优先级带数据可读
- POLLPRI 高优先级可读数据
- POLLOUT普通或带外数据可写
- POLLWRNORM-数据可写
- POLLWRBAND-优先级带数据可写
- POLLERR 发生错误
- POLLHUP 发生挂起 POLLNVAL 描述字不是一个打开的文件
nfds 监控数组中有多少文件描述符需要被监控 timeout 毫秒级等待
- -1:阻塞等,#define INFTIM -1 Linux中没有定义此宏
- 0:立即返回,不阻塞进程
- 0:等待指定毫秒数,如当前系统时间精度不够毫秒,向上取值
如果不再监控某个文件描述符时,可以把pollfd中,fd设置为-1,poll不再监控此 pollfd,下次返回时,把revents设置为0。
ppoll GNU定义了ppoll(非POSIX标准),可以支持设置信号屏蔽字,可参考poll模型自 行实现C/S
3. epoll
epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并 发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结 果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点 原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件 异步唤醒而加入Ready队列的描述符集合就行了。
目前epell是linux大规模并发网络程序中的热门首选模型。
epoll除了提供select/poll那种IO事件的电平触发(Level Triggered)外,还提 供了边沿触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少 epoll_wait/epoll_pwait的调用,提高应用程序效率。
一个进程打开大数目的socket描述符cat /proc/sys/fs/file-max
4. 总结
本文介绍了Linux多路复用的三种技术:select、poll、epoll。