如何遍历 fd_set

新手上路,请多包涵

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

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

谢谢

原文由 Andreas 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 810
2 个回答

Select 设置与集合中文件描述符相对应的位,因此,如果您只对少数几个感兴趣(并且可以忽略其他),则无需遍历所有 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
}

编辑

这是 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;

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

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

我想在这里澄清一件事:

“循环通过所有连接的套接字”并不意味着您实际上正在读取/对连接进行操作。 FD_ISSET() 仅检查 fd_set 中位于连接分配的 file_descriptor 编号的位是否已设置。如果效率是您的目标,那么这不是最有效的吗?使用启发式?

请告诉我们这种方法有什么问题,以及您试图使用替代方法来实现什么。

原文由 lalli 发布,翻译遵循 CC BY-SA 2.5 许可协议

您必须在调用 select() 之前填写 fd_set 结构,您不能直接传入原始的 std::set 套接字。 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] );
}

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] );
    }
}

原文由 Remy Lebeau 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题