如何遍历fd_set

And*_*eas 17 c c++ select file-descriptor

我想知道是否有一种简单的方法来迭代fd_set?我想这样做的原因是不必遍历所有连接的套接字,因为select()改变这些fd_sets只包括我感兴趣的那些.我也知道使用一种不打算直接访问的类型的实现通常是一个坏主意,因为它可能在不同的系统中有所不同.但是,我需要一些方法来做到这一点,而且我的想法已经不多了.所以,我的问题是:

如何遍历fd_set?如果这是一个非常糟糕的做法,除了循环所有连接的套接字之外,还有其他方法可以解决我的"问题"吗?

谢谢

Rem*_*eau 11

你必须在调用select()之前填写一个fd_set结构,你不能直接传入你的原始std ::套接字.select()然后相应地修改fd_set,删除任何未"设置"的套接字,并返回剩余的套接字数.你必须遍历生成的fd_set,而不是你的std :: set.无需调用FD_ISSET(),因为生成的fd_set只包含准备就绪的"set"套接字,例如:

fd_set read_fds;
FD_ZERO(&read_fds);

int max_fd = 0;

read_fds.fd_count = connected_sockets.size();
for( int i = 0; i < read_fds.fd_count; ++i ) 
{
    read_fds.fd_array[i] = connected_sockets[i];
    if (read_fds.fd_array[i] > max_fd)
      max_fd = read_fds.fd_array[i];
}

if (select(max_fd+1, &read_fds, NULL, NULL, NULL) > 0)
{ 
    for( int i = 0; i < read_fds.fd_count; ++i ) 
        do_socket_operation( read_fds.fd_array[i] ); 
} 
Run Code Online (Sandbox Code Playgroud)

FD_ISSET()更常出现的地方是使用select()进行错误检查,例如:

fd_set read_fds;
FD_ZERO(&read_fds);

fd_set error_fds;
FD_ZERO(&error_fds);

int max_fd = 0;

read_fds.fd_count = connected_sockets.size();
for( int i = 0; i < read_fds.fd_count; ++i ) 
{
    read_fds.fd_array[i] = connected_sockets[i];
    if (read_fds.fd_array[i] > max_fd)
      max_fd = read_fds.fd_array[i];
}

error_fds.fd_count = read_fds.fd_count;
for( int i = 0; i < read_fds.fd_count; ++i ) 
{
    error_fds.fd_array[i] = read_fds.fd_array[i];
}

if (select(max_fd+1, &read_fds, NULL, &error_fds, NULL) > 0)
{ 
    for( int i = 0; i < read_fds.fd_count; ++i ) 
    {
        if( !FD_ISSET(read_fds.fd_array[i], &error_fds) )
            do_socket_operation( read_fds.fd_array[i] ); 
    }

    for( int i = 0; i < error_fds.fd_count; ++i ) 
    {
        do_socket_error( error_fds.fd_array[i] ); 
    }
} 
Run Code Online (Sandbox Code Playgroud)


lal*_*lli 6

选择设置与集合中的文件描述符对应的位,因此,如果您只对少数几个感兴趣(并且可以忽略其他),则需要 - 不迭代所有fds,只测试您感兴趣的那些文件描述符.

if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
   perror("select");
   exit(4);
}

if(FD_ISSET(fd0, &read_fds))
{
   //do things
}

if(FD_ISSET(fd1, &read_fds))
{
   //do more things
}
Run Code Online (Sandbox Code Playgroud)

编辑
这是fd_set结构:

typedef struct fd_set {
        u_int   fd_count;               /* how many are SET? */
        SOCKET  fd_array[FD_SETSIZE];   /* an array of SOCKETs */
} fd_set;
Run Code Online (Sandbox Code Playgroud)

其中,fd_count是设置的套接字数(因此,您可以使用此方法添加优化),fd_array是一个位向量(大小为FD_SETSIZE*sizeof(int),取决于机器).在我的机器中,它是64*64 = 4096.

那么,你的问题基本上是:在位向量(大小约为4096位)中找到1位位置的最有效方法是什么?

我想在这里澄清一件事:
"遍历所有连接的套接字"并不意味着你实际上正在读取/做连接的东西.FD_ISSET()仅检查位于连接的已分配file_descriptor编号的fd_set中的位是否已设置.如果效率是你的目标,那么这不是最有效的吗?使用启发式?

请告诉我们这种方法有什么问题,以及您尝试使用备用方法实现的目标.

  • fd_set本身的定义取决于操作系统.Linux的fd_set没有fd_count成员. (4认同)
  • 如果这不是[正确/你想要]的答案,为什么它被标记为答案? (3认同)