C语言 如何使用poll()检测超时的客户端



我正在编写一个非分叉服务器,使用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()说,这是ok的。

如何通过检测到这个沉默的客户端并关闭它的连接来解决这个问题?

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

然后我每60秒使用一个警报信号,并运行lastseen数组,将它们的时间戳与当前时间戳进行比较,并在> 60秒内拆除每个空闲的连接。

或者线程也可以这样做以避免发出信号。你有什么建议来解决这个问题?

(注意,我用libevent做了实验,它非常好。但是,我不得不放弃它,因为我找不到将SSL/TLS添加到已经连接的套接字的支持。考虑STARTTLS

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

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

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

最新更新