【问题标题】:select() times out immediately after long runtime (C++)select() 在长时间运行后立即超时 (C++)
【发布时间】:2011-07-27 22:37:39
【问题描述】:

大多数情况下,这段代码运行良好。但有时当可执行文件运行了一段时间后,select() 似乎立即超时,然后进入一个奇怪的状态,它不断被调用,立即超时,一遍又一遍。然后必须从外面杀死它。

我的猜测是标准输入超时更改的方式有问题 - 这就是 select 阻塞的原因。

在 StackOverflow 上环顾四周,大多数人的 select() 问题似乎都可以通过确保每次都使用宏(FD_ZERO 和 FD_SET)重置并使用正确的初始参数进行选择来解决。我不认为这些是这里的问题。

int            rc     = 0;
fd_set         fdset;
struct timeval timeout;

// -- clear out the response -- //
readValue = "";

// -- set the timeout -- //
timeout.tv_sec = passedInTimeout;  // 5 seconds
timeout.tv_usec = 0;

// -- indicate which file descriptors to select from -- //
FD_ZERO(&fdset);
FD_SET(passedInFileDescriptor, &fdset); //passedInFileDescriptor = 0

// -- perform the selection operation, with timeout -- //
rc = select(1, &fdset, NULL, NULL, &timeout);


if (rc == -1)  // -- select failed -- //
{
    result = TR_ERROR;
}
else if (rc == 0)  // -- select timed out -- //
{
    result = TR_TIMEDOUT;
}
else 
{
    if (FD_ISSET(mFileDescriptor, &fdset))
    {
        if(rc = readData(readValue) <= 0)
        {
            result = TR_ERROR;
        }
    } else {
       result = TR_SUCCESS;
    }
}

【问题讨论】:

  • 你能在rc == 0的情况下添加一些调试代码吗?记录passedInFileDescriptor的值,timeoutFD_ISSET(mFileDescriptor, &amp;fdset)中的字段;如果这个总结的代码是正确的,就会出现一些可疑的事情,你可能需要更多的数据来尝试确定它。
  • 调用 ioctl() 和 tcsetattr() 更改文件描述符的内容。打开文件的公共文件描述符可以在父子之间共享,并且子子可以更改描述符,然后传播到父子。这假设您自己没有进行 ioctl() 或类似的调用。我正在考虑文件的非阻塞行为。
  • 文件描述符是否已关闭或到达eof?

标签: c sockets select-function


【解决方案1】:

请注意,“选择”的一些实现严格适用于规范: “nfds 是三组中编号最高的文件描述符,加 1”。 因此,您最好将“1”更改为“passedInFileDescriptor+1”作为第一个参数。 我不知道这是否可以解决您的问题,但至少您的代码变得更加......呃......“传统”;)

再见

【讨论】:

  • 谢谢!我修改了它。行为没有改变,但我很高兴更正确。
  • 嗨! “mFileDescriptor”总是等于“passedInFileDescriptor”吗?如果不是真的,可能会发生一些奇怪的事情。例如:如果“mFileDescriptor”错误且“FD_ISSET”成功且“readData() > 0”会发生什么? “结果”在您的代码中未定义,所以......嗯......好吧,我的只是一个提示。再见!
【解决方案2】:

在某些操作系统上,timeout 在调用 select 时会被修改以反映未睡觉的时间量。在您的示例中,您似乎没有重复使用 timeout,但请确保您确实在每次调用 select 之前将其重新初始化为 5 秒。

【讨论】:

    【解决方案3】:

    我遇到了同样的问题,它在 windows 上运行良好,但在 linux 上运行良好,我将 maxfd 设置为最后一个套接字 + 1。它在长时间运行后会定期发生。我在接受时拿起连接,然后第一次调用 select 定期超时。

    【讨论】:

      【解决方案4】:

      看这段代码:

      if (FD_ISSET(mFileDescriptor, &fdset))
      {
          if(rc = readData(readValue) <= 0)
          {
              result = TR_ERROR;
          }
      } else { 
         result = TR_SUCCESS;
      }
      

      这里有两件事困扰着我:

      1. 如果您的 FD 中没有数据(例如发生错误), FD_ISSET() 将返回 false 并且您的函数返回 TR_SUCCESS!?
      2. FD_SET(passedInFileDescriptor, &amp;fdset),但检查另一个 值:FD_ISSET(mFileDescriptor, &amp;fdset)。如果 mFileDescriptor != passInFileDescriptor 在某些时候,你会落入我的第一个 假设。

      它应该是这样的:

      if (FD_ISSET(passedInFileDescriptor, &fdset))
      {
          if(rc = readData(readValue) <= 0)
          {
              result = TR_ERROR;
          }
          else 
          {
              result = TR_SUCCESS;
          }
      }
      else
      {
          result = TR_ERROR;
      }
      

      没有?

      (编辑:另外,this answer 还指出了您使用 select() 的问题是 high_fd 值不好)

      另一个编辑:嗯,看起来那些家伙再也没有回来......令人沮丧。

      【讨论】:

        猜你喜欢
        • 2015-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-01
        • 2019-02-22
        • 1970-01-01
        • 2014-05-30
        • 1970-01-01
        相关资源
        最近更新 更多