有没有办法让HTTP::Daemon
以某种方式检测客户端何时断开连接(例如因为超时(,然后自行终止连接?
现在,我是这样写我的服务器:
my $response;
try {
local $SIG{ALRM} = sub { die __TIMEOUT__ };
alarm 180;
&process_query;
alarm 0;
$response = new HTTP::Response(200);
}
catch {
if ( $_ eq __TIMEOUT__ ) {
$response = new HTTP::Response(504);
}
else {
$response = new HTTP::Response(500);
}
};
$client->send_response($response);
这只是假设客户端将在180秒后放弃,这可能是真的,也可能不是真的。只要客户一直在等待响应,我就愿意继续处理,但时间不会更长。
通常,只要您在处理数据(单线程(,它就不会检查文件描述符,因此它不会检测到问题。我看到以下选项:
- 在
process_query
内部不时检查$client
套接字是否可使用IO::Select
或类似程序读取。可读性可以是客户端关闭连接或发送更多数据,例如HTTP管道。您可以尝试使用recv
和MSG_PEEK
检查是否有数据或eof(例如,客户端关闭(,但您将无法检测到后面是否有更多的数据,因为在获得eof之前,您必须先读取数据 - 如果您在UNIX上,您可以使用一个很少使用的功能:使用
fcntl($client,F_SETOWN,$$)
,如果$client
套接字上有新事件,您可以让内核向您发送SIGIO
信号。但是我上一次使用这个Perl时并没有正确处理它,我不得不通过显式调用fcntl
-系统调用:syscall(SYS_fcntl,fileno($client),F_SETOWN,$$);
来解决它。一旦设置好,就可以像现在处理ALRM
一样处理IO
信号
在任何情况下:来自客户端的eof仅意味着客户端将不再写入(请求结束(。它可能仍然愿意读取您的数据(单方面关闭(。只有在发送数据并获得SIGPIPE
后,您才能知道客户端是否关闭以进行读取。没有办法绕过它,这就是带有BSD套接字的TCP的工作方式。