select() 在长时间运行后立即超时 (C++)
Posted
技术标签:
【中文标题】select() 在长时间运行后立即超时 (C++)【英文标题】:select() times out immediately after long runtime (C++) 【发布时间】:2011-07-27 22:37:39 【问题描述】:大多数情况下,这段代码运行良好。但有时当可执行文件运行了一段时间后,select() 似乎立即超时,然后进入一个奇怪的状态,它不断被调用,立即超时,一遍又一遍。然后必须从外面杀死它。
我的猜测是标准输入超时更改的方式有问题 - 这就是 select 阻塞的原因。
在 *** 上环顾四周,大多数人的 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
的值,timeout
和FD_ISSET(mFileDescriptor, &fdset)
中的字段;如果这个总结的代码是正确的,就会出现一些可疑的事情,你可能需要更多的数据来尝试确定它。
调用 ioctl() 和 tcsetattr() 更改文件描述符的内容。打开文件的公共文件描述符可以在父子之间共享,并且子子可以更改描述符,然后传播到父子。这假设您自己没有进行 ioctl() 或类似的调用。我正在考虑文件的非阻塞行为。
文件描述符是否已关闭或到达eof?
【参考方案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;
这里有两件事困扰着我:
-
如果您的 FD 中没有数据(例如发生错误),
FD_ISSET() 将返回
false
并且您的函数返回
TR_SUCCESS
!?
你FD_SET(passedInFileDescriptor, &fdset)
,但检查另一个
值:FD_ISSET(mFileDescriptor, &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 值不好)
另一个编辑:嗯,看起来那些家伙再也没有回来......令人沮丧。
【讨论】:
以上是关于select() 在长时间运行后立即超时 (C++)的主要内容,如果未能解决你的问题,请参考以下文章