【问题标题】:How to detect a timed out client with poll()?如何使用 poll() 检测超时的客户端?
【发布时间】:2017-02-25 12:16:08
【问题描述】:

我正在编写一个非分叉服务器,使用 poll() 进行多个同时连接。它工作正常,除了我对如何以正确的方式检测超时有疑问。

假设我有以下代码:

#define POLL_SIZE 512

struct pollfd poll_set[POLL_SIZE];
timeout = 60000; // 60 secs

// setup server_sockfd with socket(), bind(), listen(), ...

poll_set[0].fd = server_sockfd;
poll_set[0].events = POLLIN;
numfds = 1;

while(1) {
   rc = poll(poll_set, numfds, timeout);
   if(rc == 0){
      // handle timeout
   }

   for(fd_index = 0; fd_index < numfds; fd_index++) {
      if(poll_set[fd_index].revents & POLLIN) {
         // accept new connection or handle established connections
      }
   }
}

假设,我有 15 个客户端连接,14 个客户端正在发送和接收数据,但是一个客户端是静默的,没有数据传入或传出,即。只是占用服务器上的一个套接字。

现在,问题是 poll() 无法发现这个特定的客户端,因为所有其他 14 个客户端都在提供数据,所以 poll() 说,没关系。

您将如何通过检测此静默客户端并关闭其连接来解决此问题?

目前,我没有更好的办法,然后创建一个 time_t lastseen[POLL_SIZE] 数组,并在从客户端读取数据或发送到客户端时跟踪给定连接的时间戳。

然后我每 60 秒使用一次警报信号,并遍历 lastseen 数组,将它们的时间戳与当前时间戳进行比较,然后断开每个空闲 > 60 秒的连接。

或者也许一个线程可以做同样的事情来避免信号。你有什么建议来解决这个问题?

(请注意,我尝试了 libevent,它非常好。但是,我不得不放弃它,因为我找不到将 SSL/TLS 添加到已连接的套接字的支持。想想 STARTTLS)

【问题讨论】:

    标签: c sockets networking timeout


    【解决方案1】:

    检测与套接字相关的错误不是 poll 的工作。它所做的只是表明一个或多个套接字是否已准备好进行读写操作。如果任何等待的套接字发生错误,则轮询将该套接字标记为就绪(实际上它由操作系统标记)并且 POLLERR 标志在 revents 字段中指示。

    超时怎么办。通常超时不是传输层错误(因此不被套接字跟踪)。您需要自己跟踪它。例如,您可以记住上次从套接字读取的时间戳(参见 clock_gettime(CLOCK_MONOTONIC, ...))并将轮询中​​的超时设置为与该套接字相关的所有超时的最小值。超时过期后,您需要检查每个套接字是否过期。

    还可以考虑使用 epoll - 在一次轮询中处理大量套接字时速度要快得多。并且对于最近的超时选择,您可以使用堆数据结构。所以你可以用O(log n)执行时间来管理所有的socket。

    【讨论】:

    • 谢谢 Dmitry,然后我将自己跟踪给定套接字的时间戳。比
    • 感谢clock_gettime 的提示。顺便提一句。虽然我开发的软件主要在 Linux 上运行,但我想继续支持支持 poll 的其他操作系统(例如 Freebsd 等)。
    猜你喜欢
    • 1970-01-01
    • 2013-11-16
    • 2011-03-01
    • 2012-06-25
    • 2013-11-13
    • 2012-01-10
    • 2018-03-31
    • 2012-12-06
    相关资源
    最近更新 更多