Linux select分析
select的作用
初学socket时,习惯使用connent、accept、recv或者recvfrom来阻塞程序。然而使用select可以完成非阻塞方式,监视需要被监视的文件描述符的变化情况——读写或异常。
相关数据结构
fd_set,实际是一个long int 类型的数组,其中的每一个 bit 代表一个文件描述符,一般最多表示1024个文件描述符 (sys/select.h)
1 /* fd_set for select and pselect. */ 2 typedef struct 3 { 4 /* XPG4.2 requires this member name. Otherwise avoid the name 5 from the global namespace. */ 6 #ifdef __USE_XOPEN 7 __fd_mask fds_bits[__FD_SETSIZE / __NFDBITS]; 8 # define __FDS_BITS(set) ((set)->fds_bits) 9 #else 10 __fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS]; 11 # define __FDS_BITS(set) ((set)->__fds_bits) 12 #endif 13 } fd_set;
关于fd_set的一些操作:(宏定义)
FD_CLR(fd, &fdset) // Clears the bit for the file descriptor fd in the file descriptor set fdset. FD_ISSET(fd, &fdset) // Returns a non-zero value if the bit for the file descriptor fd is set in the file descriptor set pointed to by fdset, and 0 otherwise. FD_SET(fd, &fdset) // Sets the bit for the file descriptor fd in the file descriptor set fdset. FD_ZERO(&fdset) // Initializes the file descriptor set fdset to have zero bits for all file descriptors.
函数
int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout); /* int maxfdp:集合中所有文件描述符的范围,为所有文件描述符的最大值加1。 fd_set *readfds:要进行监视的读文件集。 fd_set *writefds :要进行监视的写文件集。 fd_set *errorfds:用于监视异常数据。 struct timeval* timeout:select的超时时间,它可以使select处于三种状态: */
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
- (1)执行fd_set set; FD_ZERO(&set); 则set用位表示是0000,0000。
- (2)若fd=5,执行FD_SET(fd,&set); 后set变为0001,0000(第5位置为1)
- (3)若再加入fd=2,fd=1,则set变为0001,0011
- (4)执行 select(6,&set,0,0,0) 阻塞等待
- (5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。