我正在编写一个非分叉服务器,使用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秒使用一次警报信号,然后运行最后一个数组,将它们的时间戳与当前时间戳进行比较,并拆除每个空闲连接&gt; 60秒。
或许线程可以做同样的事情以避免发信号。您有什么建议来解决这个问题?
(请注意,我尝试了libevent,它非常好。但是,我不得不放弃它,因为我无法找到支持将SSL / TLS添加到已连接的套接字。想想看STARTTLS)
答案 0 :(得分:0)
检测与套接字相关的错误不是poll的工作。所有这一切都表明一个或多个套接字是否已准备好进行读写操作。如果任何等待套接字发生错误,则轮询标记套接字已准备好(实际上由OS标记)和POLLERR标志在revents字段中指示。
超时怎么样?通常,超时不是传输层错误(因此不会被套接字跟踪)。您需要自己跟踪它。例如,您可以记住最后一次从套接字读取的时间戳(请参阅clock_gettime(CLOCK_MONOTONIC,...))并将轮询中的超时设置为与该套接字相关的所有超时中的最小值。超时到期后,您需要检查每个套接字是否过期。
另外考虑使用epoll - 在一次调查中对于大量套接字来说要快得多。而且,为了选择最近的超时,您可以使用堆数据结构。因此,您可以使用O(log n)
执行时间来管理所有套接字。