最近遇到了fd_set, 虽然早早的听说是将描述符按位存储, 但不清楚其实现, 今天就来仔细的看看其实现
/* The fd_set member is required to be an array of longs. */
//从注释可以看出的是, fd_set本质是一串long int类型的数组
typedef long int __fd_mask;
/* Some versions of <linux/posix_types.h> define this macros. */
#undef __NFDBITS
/* It's easier to assume 8-bit bytes than to get CHAR_BIT. */
#define __NFDBITS (8 * (int) sizeof (__fd_mask)) //32, __fd_mask是long int, 占4字节, 共32位
//下两个宏是用在运算过程中的,先放着
#define __FD_ELT(d) ((d) / __NFDBITS)
#define __FD_MASK(d) ((__fd_mask) 1 << ((d) % __NFDBITS))
看到这里, 就可以粗略的设想一下fd_set应该是long型数组,但根据我们已知, 其是按位存储的, 那我们可能设想到的是c++ 中STL的deque, 当然差别不小...
好了接下去看看.
/* fd_set for select and pselect. */
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]; // __FD_SETSIZE=1024 __NFDBITS=32,默认__FD_SETSIZE为1024, 那fds_bits默认就是长度为32的long数组
# 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就是这样!是一个默认大小不可变的数组, 0-31位(即long数组第一个元素)存储大小小于32的描述符,第二位则可存储32-63,共可以存1024个fd
继续看操作:
#define __FD_SET(d, set) \
((void)(__FDS_BITS(set)[__FD_ELT(d)] |= __FD_MASK(d)))
#define __FD_CLR(d, set) \
((void)(__FDS_BITS(set)[__FD_ELT(d)] &= ~__FD_MASK(d)))
#define __FD_ISSET(d, set) \
((__FDS_BITS(set)[__FD_ELT(d)] & __FD_MASK(d)) != 0)
先看__FD_SET,首先__FD_ELT是将要加入的fd与__NFDBITS直接相除,所得的是这个fd要存储在long数组的哪个元素中
__FD_MASK(d)则是在与__NFDBITS求余后将long类型的1左移,这样一来就得到了这个新fd在某个long数组元素中占的是哪一位了!
最后进行或运算, 这样就能将该fd对应的位置1,存储成功!
了解了__FD_SET, 那么其他两个就不难理解了