【问题标题】:Time out idle connections in epoll based server基于 epoll 的服务器中的空闲连接超时
【发布时间】:2018-08-09 09:16:49
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 如果您使用SO_RCVTIMEO,当连接超时时您会收到epoll 通知吗?您对epoll 使用了哪些选项?您使用的是EPOLLHUP 还是EPOLLRDHUP?见stackoverflow.com/questions/27175281/epollrdhup-not-reliable
  • @AndrewHenle 我已经在客户端套接字上打开了SO_RCVTIMEO,我还设置了 epoll 来监听EPOLLHUPEPOLLRDHUP。在通过 netcat 打开连接并等待指定超时空闲后,不会触发 epoll 事件并且 read() 调用不会返回错误 EAGAINEWOULDBLOCK,即使我在超时后发送了一些数据。看起来SO_RCVTIMEO 对非阻塞套接字(?)没有影响。

标签: c sockets network-programming nonblocking epoll


【解决方案1】:

由于您知道每个套接字的 last_active 时间,您可以计算下一个套接字应该超时的时间(假设在此期间不再发生 I/O)并将超时参数传递给 epoll_wait()使其在那个时候唤醒,以便您可以执行连接关闭。

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

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

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

【讨论】:

  • 顺便说一句,如果您担心必须过于频繁地从优先级队列中删除并重新插入条目,您可以添加一个优化,仅当套接字的 @987654324 时才执行删除和重新插入@ 值自上一次 send()recv() 调用以来实际上已经发生了变化——然后通过将 last_value 值存储在更大粒度的单位(例如秒或分钟而不是例如毫秒或微秒),这样它们就不会经常变化。 (不过,这可能不是真的必要,因为 O(log(N)) 仍然很快)
猜你喜欢
  • 2014-07-06
  • 2017-12-06
  • 2020-04-29
  • 1970-01-01
  • 2017-07-19
  • 2017-08-27
  • 1970-01-01
  • 2017-04-19
  • 1970-01-01
相关资源
最近更新 更多