与多线程和多进程相比,I/O多路复用的最大优势是系统开销小,系统不需要建立新的进程或者线程,也不必维护这些线程和进程。
主要应用:
(1)客户程序需要同时处理交互式的输入和服务器之间的网络连接
(2)客户端需要对多个网络连接作出反应
(3)TCP服务器需要同时处理多个处于监听状态和多个连接状态的套接字
(4)服务器需要处理多个网络协议的套接字
(5)服务器需要同时处理不同的网络服务和协议
select()函数
#include <sys/time.h> int select(int nfds, fd_set *readfds,fd_set *wtitefds, fd_set *errnofds, struct timeval *timeout)
注意:描述符不受限与套接字,任何描述符都行
nfds:select()函数监视的描述符数的最大值,一般取监视的描述符数的最大值+1,
其上限设置在sys/types.h中有定义
#define FD_SETSIZE 256
readfds:select()函数监视的可读描述符集合
wtitefds:select()函数监视的可写描述符集合
errnofds:select()函数监视的异常描述符集合
timeout:select()函数监视超时结束时间,取NULL表示永久等待
timeout告知内核等待所指定描述字中的任何一个就绪可花多少时间。其timeval结构用于指定这段时间的秒数和微秒数。
struct timeval{ long tv_sec; //seconds long tv_usec; //microseconds };
这个参数有三种可能:
(1)永远等待下去:仅在有一个描述字准备好I/O时才返回。为此,把该参数设置为空指针NULL。
(2)等待一段固定时间:在有一个描述字准备好I/O时返回,但是不超过由该参数所指向的timeval结构中指定的秒数和微秒数。
(3)根本不等待:检查描述字后立即返回,这称为轮询。为此,该参数必须指向一个timeval结构,而且其中的定时器值必须为0。
返回值:返回总的位数这些位对应已准备好的描述符,否则返回-1
相关宏操作:
FD_ZERO(fd_set *fdset):清空fdset与所有描述符的关系 FD_SET(int fd, d_set * fdset):建立描述符fd与fdset得关系 FD_CLR(int fd, d_set * fdset):撤销描述符fd与fdset得关系 FD_ISSET(int fd, d_set * fdset):检查与fdset联系的描述符fd是否可以读写,返回非零表示可以读写
select()函数实现IO多路复用的步骤
(1)清空描述符集合
(2)建立需要监视的描述符与描述符集合的关系
(3)调用select函数
(4)检查监视的描述符判断是否已经准备好
(5)对已经准备好的描述符进程IO操作