我正在编写类似下面的内容(直径协议),我需要实现一个计时器来监控会话暂挂状态,并在超过某个阈值时终止它们,这样做的最佳方法是什么?
请注意我正在寻找算法。
Credit-Control Application Related Parameters
Tx timer
When real-time credit-control is required, the credit-control
client contacts the credit-control server before and while the
service is provided to an end user. Due to the real-time nature
of the application, the communication delays SHOULD be minimized;
e.g., to avoid an overly long service setup time experienced by
the end user. The Tx timer is introduced to control the waiting
time in the client in the Pending state. When the Tx timer
elapses, the credit-control client takes an action to the end user
according to the value of the Credit-Control-Failure-Handling AVP
or Direct-Debiting-Failure-Handling AVP. The recommended value is
10 seconds.
答案 0 :(得分:0)
您根本不需要计时器。
当您的应用程序接受使用例如新连接时accept()
,您可以使用例如{...}来记录当前时间clock_gettime()
(特别是使用CLOCK_BOOTTIME
时钟,这需要2.6.39或更高版本的内核。
在处理过程中,特别是在发送任何响应之前,您的代码必须检查连接(时间戳)是否过早。
虽然实施起来非常简单,但非常精确,clock_gettime()
来电并不是特别快。也就是说,它本身并不是一个缓慢的调用 - 没有更快的方式来获取当前时间 - 只是根据当前时间检查时间戳确实需要每次clock_gettime()
调用,这可能导致潜在的要生成很多这样的调用。
如果性能比准确性更重要,可以使用定时器中断。在指定的时间间隔后,发生定时器中断;他们可能会被推迟。换句话说,虽然定时器中断永远不会在间隔之前触发,但是在之后允许它们随时触发。因此,超时并不像上面那么严格。
当计时器过去时,信号处理程序设置连接/超时特定标志。您的函数不会检查时间戳,而是验证该标志尚未设置。
由于Linux中的计时器是有限的资源(不稀缺,可能仅限于可能的同时客户端连接的数量) - 限制大约是getrlimit(RLIMIT_SIGPENDING)
,在我的机器上大约有四万 - ,我建议不要使用timer_create()
或timerfd_create()
为每个连接创建单独的计时器。
相反,我会使用实时信号(例如SIGRTMIN+1
)和sigwaitinfo()
上的(高优先级)线程循环,信号在所有其他线程中被阻塞,维护下一个超时事件。当sigwaitinfo()
调用返回时,它还会注册新的超时事件;这样,任何线程都可以通过创建合适的结构,将其添加到链或数组,然后提高实时信号来添加新的超时事件。 siginfo_t
结构(参见sigaction()
的定义)告知信号是由定时器生成还是通过例如定时器生成。 sigqueue()
通常,使用定时器中断通常是首选,因为它比重复比较时间戳与当前时间相比具有更少的开销,并且大多数应用程序不关心超时是否有点迟(只要它永远不会太早了)。特别是,对于一个客户端,10秒超时可能是10.0秒,对于另一个客户端则是10.1秒。
很难说在您的情况下超时是否应该是准确的。您引用的规范似乎强调最小延迟,而具有精确超时(或甚至所有客户端的相同超时)似乎并不重要。我的个人意见倾向于使用计时器中断。
无论您选择哪种方法进行超时处理,我建议您从一开始就将超时处理设计到逻辑中。在这两种情况下,您的代码都需要定期检查连接是否已超时;一种方法只是将当前时间与原始时间戳进行比较,另一种方法只是一个标志。只要您设计了超时检查,就不太可能错过任何需要检查超时条件的地方,以实现稳健可靠的操作。
希望这有帮助。