关于select函数
向来是一个比较懒惰的人,但是突然觉得应该整理一些东西,写写博客什么的。只是不知道从何处开始。昨天在看松本行弘的《代码的未来》中关于C10K问题的分析,其中涉及到了slecet函数。select函数之前只是知道,没怎么了解。然后看了一下,整理如下:
应用场景:
在很多时候,一个进程要处理很多个文件的读写(包括socket文件),然后对于这些文件的访问经常会因为各种原因导致进程被阻塞。为了使进程不被阻塞在单个文件的访问上,可以使用select函数。首先将多个需要访问的文件描述符设置到相关的fd_set,并设置相应的超时时间,然后调用select函数当这些文件中,有文件可用或者超时时间已到后,select函数就会返回。
头文件:
#include <sys/select.h>
函数原型:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);FDj
readfds为读文件描述符集的指针,用于监控哪些文件描述符处于可读状态,writefds为写文件描述符集的指针,exceptfds为异常的文件描述符集的指针,以上三个集合中,对于不需要监视的,可以设置为NULL。fd_set本质上是一个bit 数组。对于根据相应的文件描述符映射至相对应的位置。
timeout为超时时间,如果timeout中对应的秒数和微妙数设置为0,则select不会休眠,立即返回,如果timeout设置为NULL,则会一直休眠,直到有资源处于非阻塞状态(可读、可写或者有异常)。
需要注意的是linux中,每次调用select都会修改timeout值,因此每次调用都要重新设置timeout的值
nfds为readfds、writefds和exceptfds三者中描述符最大值加1.
返回值 为int型。如果为0,则超时返回。如果-1,则有错误,并设置errno,如果大于0,则代表处于可用状态的描述符的数量。
对于fd_set,对应有四个宏,用于进行相关的控制:
1 #include <sys/types.h> 2 #include <unistd.h> 3 #include <sys/time.h> 4 #include <stdlib.h> 5 #include <sys/select.h> 6 7 int main(int argc, char* argv[]) 8 { 9 char buf[1000]; 10 int32_t reallen; 11 struct timeval timeout; 12 fd_set readfds; 13 int32_t ret; 14 while(1) 15 { 16 FD_ZERO(&readfds); 17 FD_SET(0, &readfds); 18 timeout.tv_sec = 1; 19 timeout.tv_usec = 0; 20 ret = select(1, &readfds, NULL, NULL, &timeout); 21 if (-1 == ret) 22 { 23 return -1; 24 } 25 if(FD_ISSET(0, &readfds)) 26 { 27 reallen = read(0, buf, 1000); 28 write(1, buf, reallen); 29 } 30 } 31 return 0; 32 }
select常用于socket连接的控制。其缺点主要有:
1.受制于每个进程管理描述符的数量受制于FD_SETSIZE,一般为1024,因此每次能够控制的连接数量有限
2.由于fd_set在select中会被修改,每次调用需要对所希望监控的描述符集合中的描述符依次调用FD_ISSET进行判断,影响性能。