一、select原型
#include<sys/select.h>
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
二、参数解释:
1.参数nfds是需要监视的最大文件描述值+1;
2.rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集合及异常文件描述符的集合;
3.参数timeout为结构timeval,用来设置select()的等待时间。
三、参数timeout取值
1.NULL:表示select()没有timeout,select将一直被阻塞,直到某个文件描述符发生了事件;
2.0:仅检测描述符的状态,然后立即返回,并不等待外部事件的发生;
3.特定的实际值:如果在指定的时间段里没有事件发生,select将超时返回。
四、fd_set结构
其实这个结构就是一个整型数组,更严格的说,是一个“位图”,使用位图中对应的位表示要监视的文件描述符。
select中fd_set结构不能使用与、或、非操作,只能使用相对应的操作:
1.用来消除描述词组 set中相关fd的位;
void FD_CLR(int fd,fd_set *set);
2.用来测试描述词组set中的相关fd的位是否为真;
void FD_ISSET(int fd,fd_set *set);
3.用来设置描述词组set中相关的位;
void FD_SET(int fd,fd_set *set);
4.用来消除描述词组set的全部位;
void FD_ZERO(int fd,fd_set *set);
五、函数返回值
1.执行成功则返回文件描述符状态已经改变的个数;
2.如果返回0代表在描述词状态改变之前已经超过 timeout时间,没有返回;
3.当有错误发生时则返回-1,错误原因存于error,此时参数readfd、writefd、exceptfd和timeout的值变成不可预测。
六、socket就绪条件
读就绪:
1.socket内核中,接收缓冲区中的字节数,大于等于低水位标记SO_RCVLOWAT。此时就可以无阻塞的读该文件描述符,并且返回值大于0;
2.socket TCP通信中,对端关闭连接,此时对该socket读,则返回0(四次挥手);
3.监听的socket上有新的连接请求;
4.socket上有未处理的错误。
写就绪:
1.socket内核中,发送缓冲区中的可用字节数(发送缓冲区的空闲位置大小),大于等于低水位标记SO_RCVLOWAT。此时可以无阻塞的写,并且返回值大于0;
2.socket的写操作被关闭。对一个写操作被关闭的socket进行写操作,会触发SIGPIPE信号;
3.socket使用非阻塞connect连接成功或失败之后;
4.socket上有未读取的错误;
异常就绪:
socket上带外数据。关于带外数据,和TCP紧急模式相关(TCP协议头中的紧急指针字段)。
七、select的特点
1.可监控的文件描述符个数取决于sizeof(fdset)的值;
2.将fd假如select监控集的同时,还要使用一个数据结构array保存放到 select监控集中的fd。
八、select缺点
1.每次调用select,都需要手动设置fd集合,从接口使用角度来说非常不便;
2.每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd时会很大;
3.同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大;
4.select支持的文件描述符数量有限。