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()中重启定时器的主要内容,如果未能解决你的问题,请参考以下文章
java网络编程Socket中SO_LINGER选项的用法解读