基于 epoll 的服务器中的空闲连接超时

Time out idle connections in epoll based server

我正在用 c 编写一个 tcp 服务器,它使用 epoll() i/o 多路复用来管理并发连接。我想使空闲时间超过允许时间的连接超时。

到目前为止,我保留了一个与每个连接关联的 last_active time_t 变量,我在事件处理程序中将其更新为当前时间。在此之前,我检查自上次事件以来是否超过了允许的时间,如果是,我终止连接。

到目前为止一切顺利,但这并不是我真正想要的,因为超时仅在第一个超时事件上触发,但如果连接保持不活动状态,我的代码直到它变为 "active" 再次.

我在基于 select() 的服务器中看到的方法是在事件循环的每次迭代期间线性遍历兴趣集并清除那里的非活动连接。这在 select 中不是问题,因为无论如何您都必须执行此遍历,但我恰好使用 epoll() 来避免必须执行此操作。如果我这样做,epoll 并不比 select.

我还研究了套接字选项,我发现最接近的是 SO_RCVTIMEO,如果它等待的时间超过指定的时间,这会使 read()/recv() return 出错时间。但是由于我正在使用 i/o 多路复用并且套接字处于非阻塞模式,所以这没有任何意义,因为套接字不会阻塞。

我将不胜感激有关如何解决此问题的任何见解。非常感谢。

因为你知道每个套接字的last_active时间,你可以计算下一个套接字应该超时的时间(假设在过渡期间不再发生I/O)并通过在 epoll_wait() 的超时参数中使其在那个时候唤醒,以便您可以执行连接关闭。

这就留下了问题的另一部分——您希望能够执行该计算,而无需在事件循环的每次迭代中遍历所有套接字。

您可以通过维护支持以高效(例如 O(1) 或 O(log(N)) 方式查找最低优先级元素的数据结构(例如 priority queue)来做到这一点。在这种情况下,您可以使用套接字的 last_active 值作为其优先级值。然后在事件循环的每次迭代之前,您查询数据结构以找出哪个套接字具有最低优先级(又名哪个套接字将是下一个超时并需要断开连接(如果没有进一步的流量发生),并使用它来设置您的 epoll_wait() 超时。

请注意,为了维护数据结构,您需要在每次套接字发送或接收数据时更新它(以调整其优先级以反映其新鲜度 activity,方法是从结构,然后使用 updated/current last_time/priority 值重新插入它),但这也是一个 O(log(N)) 操作,因此开销不应太高。