但你需要在一个线程里面处理多个描述符时,一般需要使用I/O复用,select是I/O复用的一种。
原型
int select(int nfds, fd_set *readst, fd_set *writefd, fd_set *exceptfd, const struct timeval *timeout);
参数解析
nfds
加这个参数是为了提高select的效率,linux里一个进程打开的描述符有限,一般是1024。当然如果你用select那么肯定是用不到1024个,从另一方面来讲,当描述符过多的时候,使用select也是不合适的。在这里,nfds表示select将要检测的描述符有多少个,事实上它只检测
0 - (nfds-1)。如果描述大于或者等于nfds,那么不管上面三个fd_set有没有set,select都不会去检测。
readset,writeset,excepte
你需要让select检测的描述符集合,注意两点。1:它们受nfds限制; 2:如果描述符出现异常,select会直接返回,并且三个fd_set都会被置1(前提是它们不会NULL)。
timeout
struct timeval{
long time_sec;
long time_usec;
}
被设置表示超时时间。0表示select直接返回,返回值为0;NULL表示一直等待下去;所以如果三个fd_set均为NULL,那么select是一个微妙级(内核事实上达不到这个级别)的定时器。
《UNIX网络编程卷一》当中说到timeout加const修饰,表示在select里面不会被修改,也就是为如果并没有到超时时间select就返回了,timeout是不会被更新为剩余秒数的。如果要知道select阻塞了多长时间,那么通过取系统时间来做。
注意:事实上linux下面会修改,返回的就是剩余时间,这点与书上不符合。
注意事项:
1:fd_set就是一个数组,在这个里面每一个描述符占一位。linux默认是1024,所以不要超过这个值。另外如果描述过多,不建议使用select,效率过低。
2:每次调用select都必须重新设置fd_set,因为select在返回时除了就绪的描述符位,其他位均会被置0。