如何在select中使用位掩码签入fd_集?

如何在select中使用位掩码签入fd_集?,c,bit-manipulation,C,Bit Manipulation,根据这篇文章: select()每个文件仅使用(最多)三位数据 描述符,而poll()通常每个文件描述符使用64位。 因此,在每个系统调用中,invoke poll()都需要复制更多内容到 内核空间。select()的小胜利 以下是fd_集的实现(位于 因此,最终,fd_集只是一个long的数组。它还被写入: 调用FD_SET时,使用套接字编号作为索引将位设置为1: 这意味着,如果我得到一个套接字fd编号5,索引为5的元素将被选择,它的第一位将从0翻转到1。由于select()使用3位,我猜其他

根据这篇文章:

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

以下是fd_集的实现(位于

因此,最终,fd_集只是一个
long
的数组。它还被写入:

调用FD_SET时,使用套接字编号作为索引将位设置为1:

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

此外,如上所述,
poll()
使用64位进行检查。为什么
poll
需要检查
pollfd
struct中的每一位?以下是
pollfd
struct:

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。我知道检查位标志的常用方法是使用
和(&)
运算符过滤掉其他不相关的位。这适用于这种情况吗?

原因
选择()
使用
long
s是将许多位编码为单个变量值。
long
通常可以包含32位(有时是64位),这意味着可以使用
long
类型的单个值表示32个文件集

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

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


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

它本身不使用1
long
。它使用
FD_SETSIZE
位的位字段,在这种情况下是32位长或16 64位长。通过使用long,它允许对文件使用更少的内存操作64位机器(在Unix上已经普及了20年)。他们本可以使用普通的
int
,但那样的话,他们就不会在64位机器上占优势。这只是前瞻性的想法

如果在多个文件描述符上使用“选择”,则需要为所有文件描述符留出空间。假设您要从3个套接字、SCSI设备和文件中读取,并且文件描述符的值分别为3、7、10、12和67,您将如何表示这一点?请在设置了该数字的位的位置使用位集

 00010001.00101000:00000000.00000000:00000000.00000000:00000000.00000000   00010000.00000000
    ^   ^   ^ ^                                                               ^
    0   0   1 1                                                               6 
    3   7   0 2                                                               7 
poll()通常每个文件描述符使用64位。因此,在每个系统调用中,invoke poll()需要将更多的数据复制到内核空间。select()的一个小胜利

谬误——如果您只想监视一个fd,轮询(2)将使您摆脱这64位,而对于select(),您必须复制多达12288位(3组,通常每个4096位)


此外,poll()支持值大于fd_SETSIZE的fd。

我明白了。每个套接字描述符3位,每个位驻留在每个
fd_集
上。通常一位是
select()
中的文件,根据
fd_集
上下文从0切换到1(如果套接字请求读取,则该位表示该套接字将在用于读取的
fd_set
中翻转。同时,
poll
将仅对文件描述符使用整个整数。)谢谢。您的回答验证了我在
unwind
post中的评论。现在我了解了套接字在
fd_set
中的关联方式。32个元素的数组表示1024位的限制,即1024个文件描述符(由
fd_set size
定义)。至于poll,它使用一个完整的结构来表示一个套接字描述符。但是,我认为这种方法比按位思考更容易理解。是的,这取决于需要检查多少描述符(我曾经写过一个终端muxer,它可以管理112个SCSI通信设备,再加上带有listen-fd和read/write的动态数量的套接字。使用
poll
管理这些设备会产生大量内存拷贝。
 00010001.00101000:00000000.00000000:00000000.00000000:00000000.00000000   00010000.00000000
    ^   ^   ^ ^                                                               ^
    0   0   1 1                                                               6 
    3   7   0 2                                                               7