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

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

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

到目前为止一切都那么好,但它并不是我想要的,因为超时仅在第一个超时事件中触发,但如果连接保持不活动状态,我的代码在它再次变为“活动”之前不会检测到它。

我在基于select()的服务器中看到这种方式的方法是在事件循环的每次迭代期间线性遍历兴趣集并清除那里的非活动连接。 这在选择中不是问题,因为你已经必须进行此遍历,但我正是使用epoll()来避免必须这样做。 如果我这样做,epoll并不比选择更好。

我也查看了套接字选项,我发现最接近的是SO_RCVTIMEO,这使得read()/ recv()如果等待超过指定时间则返回错误。 但由于我正在使用i / o多路复用并且套接字处于非阻塞模式,因此不会阻塞,因为套接字不会阻塞。

我很感激有关如何解决这个问题的任何见解。 非常感谢你。

由于您知道每个套接字的last_active时间,因此可以计算下一个套接字应该超时的时间(假设在过渡期间不再发生I / O)并将一个超时参数传递给epoll_wait()以导致它在那个时候醒来,这样你就可以进行连接关闭了。

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

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

请注意,为了维护数据结构,每次套接字发送或接收数据时都需要更新它(调整其优先级以反映其新活动,方法是从结构中删除套接字,然后重新插入更新/当前last_time /优先级值),但这也是一个O(log(N))操作,因此开销不应该太高。