如何在select中使用fd_set检查位掩码?

时间:2011-12-16 10:29:21

标签: c bit-manipulation

根据这篇文章poll vs select vs event-based

  

select()仅对每个文件使用(最多)三位数据   描述符,而poll()通常使用每个文件描述符64位。   在每个系统调用中,poll()因此需要将更多内容复制到   内核空间。 select()的小胜利。

这是fd_set的实现(在Advisories : multiple applications fd_set structure bitmap array index overflow

上找到)
#ifndef FD_SETSIZE
#define FD_SETSIZE  1024
#endif
#define NBBY    8       /* number of bits in a byte */
typedef long    fd_mask;
#define NFDBITS (sizeof (fd_mask) * NBBY)   /* bits per mask */
#define howmany(x,y)    (((x)+((y)-1))/(y))
typedef struct _types_fd_set {
    fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
} _types_fd_set;

#define fd_set _types_fd_set

所以,最后,fd_set只是一个long的数组。它也写得:

  

对FD_SET的调用使用套接字号作为索引将位设置为1:

这意味着,如果我得到一个套接字fd编号为5,则索引为5的元素将被选中,其第一个位将从0翻转为1.由于select()使用3位,我猜其他两个位用于发送和接收。它是否正确?为什么select()在需要3位时才使用long?

另外,如上所述,poll()使用64位进行检查。为什么poll需要检查pollfd结构中的每一位?这是pollfd结构:

struct pollfd {
    int fd;         // the socket descriptor
    short events;   // bitmap of events we're interested in
    short revents;  // when poll() returns, bitmap of events that occurred
};

结构中的总位数是64位,对于32位int和两个16位short。我知道检查位标志的通常方法是使用AND (&)运算符来过滤掉其他不相关的位。这适用于这种情况吗?

3 个答案:

答案 0 :(得分:4)

select()使用long的原因是将多个位编码为单个变量值。 long通常可以容纳32位(有时是64位),这意味着您可以使用long类型的单个值来表示32个文件集。

"每个文件三位"来自您通常用于选择读取,写入和异常的三个不同fd_set值。三个long值是(假设32位long),32 * 3 = 96位,但可以为32个不同文件选择所有三个条件,因此每个文件花费3位。这假设您为这三个集合中的32个文件中的每个文件select(),我认为这至少有点罕见。

由于poll直接使用int大小的字段表示文件描述符,而不是通过索引到位集中隐式地表示文件描述符,因此它使用更多空间。

基本上,select()的设计利用了文件描述符是*小*整数的假设,以及它们从0及以上分配。

答案 1 :(得分:4)

  

poll()通常每个文件描述符使用64位。在每个系统调用中,poll()因此需要将更多内容复制到内核空间。 select()的小胜利。

谬误 - 如果你只想监视一个fd,poll(2)会让你获得64位,而对于select(),你必须复制到12288位(3组,每组4096位)通常情况下)。

此外,poll()支持 fd ,其值大于FD_SETSIZE。

答案 2 :(得分:3)

它本身不使用1 long。它使用FD_SETSIZE位的位字段,在这种情况下为32位32位长或16位64位长。通过使用long,它允许在64位机器上使用更少的内存操作(这在Unix上已经存在了20年)。他们本可以使用普通的int但是他们在64位机器上没有优势。这只是前瞻性思维。

如果您在多个文件描述符上使用select,则需要为所有文件描述符留出空间。想象一下,你想要读取3个套接字,来自SCSI设备和文件,文件描述符值分别为3,7,10,12和67,你会如何表示?使用bitset设置该位的位。

 00010001.00101000:00000000.00000000:00000000.00000000:00000000.00000000   00010000.00000000
    ^   ^   ^ ^                                                               ^
    0   0   1 1                                                               6 
    3   7   0 2                                                               7