我正在用 c 编写一个 tcp 服务器,它使用 epoll() i/o 多路复用来管理并发连接。我想使空闲时间超过允许时间的连接超时。
到目前为止,我保留了一个与每个连接关联的 last_active time_t 变量,我在事件处理程序中将其更新为当前时间。在此之前,我检查自上次事件以来是否超过了允许的时间,如果是,我终止连接。
到目前为止一切顺利,但这并不是我真正想要的,因为超时仅在第一个超时事件上触发,但如果连接保持不活动状态,我的代码在它变为“事件”之前不会检测到它再次。
我在基于 select() 的服务器中看到的方法是线性遍历事件循环每次迭代期间设置的兴趣,并清除那里的非事件连接。这在 select 中不是问题,因为无论如何您已经必须执行此遍历,但我恰好使用 epoll() 来避免必须执行此操作。如果我这样做,epoll 并不比 select 好。
我还查看了套接字选项,我发现最接近的是 SO_RCVTIMEO,如果等待时间超过指定时间,它会使 read()/recv() 返回错误。但是由于我正在使用 i/o 多路复用并且套接字处于非阻塞模式,所以这没有任何意义,因为套接字不会阻塞。
我将不胜感激有关如何解决此问题的任何见解。非常感谢。
最佳答案
因为你知道每个套接字的最后事件时间,你可以计算下一个套接字应该超时的时间(假设在过渡期间没有更多的 I/O 发生)并将超时参数传递给 epoll_wait()
使其在那时唤醒,以便您可以执行连接关闭。
这留下了问题的另一部分——您希望能够执行该计算,而无需在事件循环的每次迭代中遍历所有套接字。
您可以通过维护支持以高效(例如 O(1) 或 O(log(N)) 方式查找最低优先级元素的数据结构(例如 priority queue )来做到这一点。在这种情况下您可以使用套接字的 last_active 值作为其优先级值。然后在事件循环的每次迭代之前,您查询数据结构以找出哪个套接字具有最低优先级(也就是哪个套接字将是下一个超时的套接字并且需要断开连接,如果没有进一步的流量发生的话),并使用它来设置你的 epoll_wait()
超时。
请注意,为了维护数据结构,您需要在每次套接字发送或接收数据时更新它(通过从结构中删除套接字然后重新插入来调整其优先级以反射(reflect)其最新事件)它具有更新的/当前的上次时间/优先级值),但这也是一个 O(log(N)) 操作,因此开销不应太高。
关于c - 基于 epoll 的服务器中的空闲连接超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51763192/