c - 为什么 FD_ISSET 在 select() 之后返回 true

标签 c sockets select

我是套接字编程的新手,我正试图彻底理解它是如何工作的,但现在我真的被 select() 困住了。

问题是在我的代码中,在 select 检测到事件并且 fd 保持设置后,似乎在下一次迭代中 FD_ISSET 将自动返回 true,就像它会忽略 select 函数一样。这个问题似乎与这个问题相同,但我做了我在那里发现的所有事情但无济于事:http://compgroups.net/comp.unix.programmer/how-does-fd_isset-return-0-after-returne/55058

我确保在 select() 之后重新初始化 timeval 变量,因为我在 Linux 上并且我知道这个函数在不同操作系统上的行为不同,我还用 FD_ZERO 重新初始化了 fd 集FD_SET 在选择之前。

我做错了什么?这是代码:

#include <stdio.h>
#include <strings.h>

#include <sys/select.h>
#include <sys/time.h>

int main () {
  struct timeval tv;

  tv.tv_sec = 5; // 5 seconds timeout
  tv.tv_usec = 0;

  fd_set afds, rfds;

  FD_ZERO(&afds);
  FD_SET(0, &afds);

  while (1) {
    rfds = afds;
    select(1, &rfds, NULL, NULL, &tv);
    // linux, reinitialize tv?
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    // so at this point after select runs the first time and detects STDIN activity
    // it will enter an infinite loop printing "fd 0 is set" (why?)
    if (FD_ISSET(0, &rfds)) {
      printf("fd 0 is set\n");
      FD_CLR(0, &rfds);
    } else {
      printf("fd 0 is NOT set\n");
    }
  }
}

问题编辑,因为我是新用户,无法回答:

事实是,当 rfds 被赋值为 afds 时,我会在 select 之前初始化 rfds,而 afds 又总是设置为 FD_ZERO(&afds); FD_SET(0, &afds);这对我仍然不起作用。

这是我的理解:

  1. 我将 stdin 文件描述符添加到 afds

  2. 进入while无限循环,rfds = afds(循环开始时rfds总是= afds)

  3. 此外,此时,FD_ISSET(0, &rfds) 将始终为 != 0

  4. select 有 5 秒的超时,所以此时如果我在 5 秒过去之前没有输入任何内容,它就会退出,UNSETTING FD_ISSET(0, &rfds) - is那对吗?所以如果没有输入任何内容,select 实际上会取消设置 fd 0。这似乎工作正常

  5. 当我在超时 之前键入内容时,问题就来了。此时FD_ISSET(0, &rfds)返回!= 0,打印fd 0 is set,然后每次循环fd都会被设置

好的,这准确吗,我没听错吗?所以实际上 select 不会等待时间过去,因为它实际上检测到 fd 已准备好并退出,设置 fd != 0 ?

这会引出一个进一步的问题:如果我需要服务器每隔一段时间自动向多个客户端发送消息(独立于它从客户端读取的内容),是否可以通过 select 和 gettimeofday 来完成调整上面的代码?

感谢您的帮助。

最佳答案

select() 是电平触发的,不是边沿触发的。当您向它传递一组文件描述符时,它会返回告诉您当前哪些是可读/可写/异常的,而不仅仅是最近更改状态的那些。

在这种情况下,每次您调用 select() 时,FD 都被标记为可读,因为您没有做任何事情来使其不可可读(比如排空可用的输入)当它出现时。

关于c - 为什么 FD_ISSET 在 select() 之后返回 true,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14485517/

相关文章:

c - 如何解释内存地址分配的顺序?

java - C 服务器和 Java 客户端。如何阅读完整的字符串?

c - rt linux中的用户程序如何访问或接收来自内核的数据?

php - Mysql select 查询性能变差

Android SQLiteDatabase SELECT 查询需要很长时间

c - "\t"、 "\r"和 "\b"在c中的作用是什么?

c - 如何读取文件并将其正确打印在数组中?

c - 如何让 NFS 支持 posix_fallocate?

javascript - 使用 Ratchet 网络套接字时如何定义路由?

SQL:这样的查询是否可以,或者是否有更有效的方法,例如使用连接?