select函数如下:
int select(nfds, readfds, writefds, exceptfds, timeout);
其中readfds、writefds、exceptfds都是fd_set指针。
select需要将分离事件的socket放入各种事件集合,如果是连接事件和可读事件,放入readfds中。
fd_set结构如下:
typedef struct
{
/* XPG4.2 requires this member name. Otherwise avoid the name
from the global namespace. */
#ifdef __USE_XOPEN
__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->fds_bits)
#else
__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->__fds_bits)
#endif
} fd_set;
针对fd_set的操作,设计了几个使用的宏。
FD_ZERO(&set);//将set的所有位置0
FD_SET(1, &set);// 将set的第1位置1,这样fd==1的文件描述字就被加进set中了
FD_CLR(4, &set);//将set的第4位置0,如set原来是10010000,则现在变为10000000,这样fd==4的文件描述字就被从set中清除了
FD_ISSET(5, &set);// 测试set的第5位是否为1,如果set原来是001100000,则返回非零,表明fd==5的文件描述字在set中;否则返回0
每个需要分离事件的socket放入fd_set中占__fds_bits的一位,fds_bits一共1024位,设计成了长度为128的long int型数组。所里理论上select可以同时分离1024个目标socket的事件。
下面举例说明,例如创建的服务socket是3,将其放入readfds后,readfds->__fds_bits[0]就为8(1<<3),此时建立了一个连接socket 4,也将其放入readfds中,readfds->__fds_bits[0]就为24(1<<3|1<<4),以此类推。
select分离到事件之后,readfds->__fds_bits就为分离到事件的socket集合,返回值为分离到事件的socket的数量。例如分离到4号socket的可读事件,则select返回1,readfds->__fds_bits[0]为16(1<<4),如果select设置了超时时间,时间达到还是没有分离到任何事件,则返回0,readfds->__fds_bits也全为0。