赞
踩
多路是指网络连接,复用指的是同一个线程。
select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述符就绪(有数据可读、可写、或者有异常),或者超时(timeout指定等待时间,如果想要立即返回,设为NULL即可)。当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。但有以下几点需要注意:
select()有个很好的优点,那就是实现简单,良好的跨平台支持。但缺点也很明显:
单个进程所打开的FD是有限制的,默认1024 ,具体可查看 /proc/sys/fs/file-max 中的FD_SETSIZE值
对socket进行的是线性扫描,即采用轮询的方法,效率较低。
每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,复制开销大。
- #include <sys/select.h>
- int select(int maxfdp, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout);
函数参数:
maxfdp:一个整数值,用以指示集合中所有文件描述符的范围,即所有文件描述符的最大值加1
readset:fd_set结构的指针,指示要监视这些文件描述符的是否可读,可以传入NULL值,表示不关心任何文件的读变化。
writeset:fd_set结构的指针,指示要监视这些文件描述符的是否可写,可以传入NULL值,表示不关心任何文件的写变化。
exceptset:fd_set结构的指针,指示要监视这些文件描述符的是否有异常,可以传入NULL值,表示不关心任何文件是否有异常。
timeout:指定select的超时时间,它有三种选择:
- 若将NULL以形参传入,select将一直处于阻塞状态,直到监视文件描述符集合中某个文件描述符发生变化为止
- 若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;
- timeout值大于0,这就是等待的超时时间
struct timeval{ long tv_sec; /*秒 */ long tv_usec; /*微秒 */ }返回值:
正常则返回就绪的文件描述符的个数,超时返回0,出错则返回-1
fd_set类型的参数可以通过以下函数进行操作:
- // 将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。
- FD_ZERO(fd_set *fdset);
-
- // 用于在文件描述符集合中增加一个新的文件描述符。
- FD_SET(fd_set *fdset);
-
- // 用于在文件描述符集合中删除一个文件描述符。
- FD_CLR(fd_set *fdset);
-
- // 用于测试指定的文件描述符是否在该集合中
- FD_ISSET(int fd,fd_set *fdset);
poll的机制与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制,因为它是基于链表来存储的。和 select 一样,文件描述符是否阻塞对 poll 是否阻塞没有任何影响。
poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。
- #include <poll.h>
- int poll ( struct pollfd * fds, unsigned int nfds, int timeout);
函数参数:
fds:存放需要检测其状态的socket描述符,且每次调用该函数后,系统不会清空这个数组,这点和select不同。
struct pollfd { int fd; // 需要监视的文件描述符,用户指定 short events; // 需要内核监视的事件,用户指定 short revents; // 实际发生的事件,内核设置 };有效的事件有:
- POLLIN 有数据可读。
- POLLRDNORM 有普通数据可读。
- POLLRDBAND 有优先数据可读。
- POLLPRI 有紧迫数据可读。
- POLLOUT 写数据不会导致阻塞。
- POLLWRNORM 写普通数据不会导致阻塞。
- POLLWRBAND 写优先数据不会导致阻塞。
- POLLMSGSIGPOLL 消息可用。
此外,revents域中还可能返回下列事件,这些事件在events域中无意义,因为它们在合适的时候总是会从revents中返回:
- POLLER 指定的文件描述符发生错误。
- POLLHUP 指定的文件描述符挂起事件。
- POLLNVAL 指定的文件描述符非法。
nfds:标记数组fds中的结构体元素的总数量
timeou:poll函数调用阻塞的时间,单位:毫秒,这里有三种情况:
timeout < 0 :这会造成 poll 永远等待。poll() 只有在一个描述符就绪时返回
timeout == 0:这种情况下,测试所有的描述符,并且 poll() 立刻返回。这允许在 poll 中没有阻塞的情况下找出多个文件描述符的状态。
time > 0:这将以毫秒为单位指定 timeout 的超时周期。poll() 只有在超时到期时返回0,除非一个描述符变为就绪
返回值:
成功时,poll()返回就绪的的文件描述符个数,如果超时,则返回0,失败返回-1
epoll()是为解决Linux内核处理大量文件描述符而提出的方案,属于select()/poll()的增强版本。其常应用于Linux下高并发服务型程序,特别是在大量并发连接中只有少部分连接处于活跃下的情况 下,能显著的提高程序的CPU利用率。
epoll采用的是事件驱动,在用户空间获取事件时,不需要去遍历被监听描述符集合中所有的文件描述符,而是遍历那些被内核I/O事件异步唤醒之后加入到就绪队列并返回到用户空间的描述符集合。
epoll提供了两种触发模式,水平触发(LT)和边沿触发(ET)。当然,涉及到I/O操作也必然会有阻塞和非阻塞两种方案。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。