我正在构建一个可以接受和处理多个客户端连接的网络服务器。我正在使用select()
这个。
现在,在此过程中,如果特定连接的套接字上没有任何活动(发送或接收),我想关闭它。因此,如果一段时间内没有来自已连接客户端的请求,我将关闭套接字。有多个这样的连接套接字,我需要对每个套接字进行监视。
我需要这个功能来创建持久连接,因为我的网络服务器必须支持 HTTP 1.1
做这个的最好方式是什么?
我建议将调用超时设置为select
下一个套接字超时之前的最短时间。然后,如果超时,关闭空闲套接字,然后重复。像这样的伪代码:
timeout = default_timeout;
foreach(socket s)
{
timeout = min(timeout, (s.last_send_or_recv_time + IDLE_TIMEOUT - now()));
}
result = select(..., timeout);
if(result == 0)
{
foreach(socket s)
{
if(now() - s.last_send_or_recv_time >= IDLE_TIMEOUT)
{
close(s);
remove_from_socket_list(s);
}
}
}
else
{
// Handle received data, update last_send_or_recv_time, etc.
}
如果您使用线程和阻塞模式,您只需要在套接字上设置一个合适的 SO_RCVTIMEOUT ,当您read()
返回 -1 时errno == EAGAIN/EWOULDBLOCK
,超时已经发生,所以您只需关闭套接字并退出线程。
如果你使用select()
它会更复杂。Adam Rosenfield 的建议从表面上看似乎是合理的,但实际上,如果其他套接字足够忙,则select()
超时可能根本不会发生,或者至少在套接字实际上变得太死后的几分钟内不会发生。如果您想严格执行超时,就像在服务器中应该的那样,您必须将最后读取时间与每个套接字相关联,并且在select()
循环的底部,遍历fd
集合,挑选出那些未准备好的 fd,检查他们的最后阅读时间,并关闭那些太死的人。