socket编程的select()中重启定时器

Posted

技术标签:

【中文标题】socket编程的select()中重启定时器【英文标题】:Restart the timer in select() of socket programming 【发布时间】:2013-04-24 00:47:15 【问题描述】:

我想使用 select() 从其他服务器接收更新并定期发送消息。考虑以下设置:

而(1) 选择(...超时= 5秒); // 一些其他代码

如果我在 t = 2 秒收到更新,则 select() 将返回并执行相应的语句。当下一个循环开始时,超时将再次设置为 5 秒。但是,它应该是 5 - 2 = 3 秒。有没有办法用正确的时间更新计时器?

我想在 select() 之前手动启动一个计时器,但是这个计时器可能与 select() 中使用的计时器不同步。并且会导致其他潜在问题。

【问题讨论】:

【参考方案1】:

根据select man page:

在 Linux 上,select() 修改超时以反映未睡眠的时间量;大多数其他实现不这样做。 (POSIX.1-2001 允许任何一种行为。)

因此,您只需重用 timeout 变量即可。仅当您真正超时时才重置其值。

正如警告所暗示的,依赖此行为会导致移植问题,因此如果您依赖此行为,请确保将其记录在案,以便在移植代码时做正确的事情。

【讨论】:

我在 windows 机器上编码,但程序将在 Linux 上测试。那么每次重新设置超时是否更好,这样可以避免移植问题? 是的,你可以这样做(正如@MichalRus 建议的那样)。或者,您可以创建一个单独的线程来执行定期处理。该线程可以只休眠 5 秒,然后循环执行某些操作。【参考方案2】:

在调用select() 之前,只需记住变量中的time(),当select() 返回时获取另一个time() 并且...在下一次while(1) 迭代中使用不是5,而是5 - difference_between_times超时值。

也许您想使用new_timeout = 5 - difference_between_times % 5,这样如果在select 返回后您的 操作需要超过5 秒...您仍将timeout 设置为5 秒间隔.

您可能不应该使用秒,而应该使用更精细的时间单位。并考虑以上是否是您真正想要的行为(使用模数)。也许当difference_between_times > 5 时,您应该等待5 秒。随心所欲,但你明白了。

【讨论】:

【参考方案3】:

当您的应用变得更加复杂时,您可能会有多个具有不同超时间隔的计时器。我们的确是。以下是我们的处理方式。

每个定时器都有一个定时器对象,time_t 是定时器到期的时间。我们将所有计时器存储在堆数据结构中,因此最快到期的计时器位于堆的根部。在执行 select() 之前,我们获取堆的根,并从计时器的到期时间中减去当前时间,并将该增量用作 select() 调用的超时时间。

Timer * t = heap->Root();
time_t now = time(0);
timeval tv;
tv.tv_sec = t->when - now;
tv.tv_usec = 0;
select( ... & tv );

【讨论】:

以上是关于socket编程的select()中重启定时器的主要内容,如果未能解决你的问题,请参考以下文章

socket编程-tcp

linux网路编程--网络超时检测

Python网络编程

java网络编程Socket中SO_LINGER选项的用法解读

Linux网络编程socket选项之SO_LINGER,SO_REUSEADDR

SO_REUSEPORT和SO_REUSEADDR与socket编程中那些关于内核自动分配的...