【问题标题】:Stop processing when client has timed out with HTTP::Daemon当客户端使用 HTTP::Daemon 超时时停止处理
【发布时间】:2014-06-17 03:34:53
【问题描述】:

有没有办法让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 秒后放弃,这可能是真的,也可能不是。只要客户一直在等待响应,我就想继续处理,但不会再等了。

【问题讨论】:

  • @Miller, process_query 会根据查询参数进行一些繁重的处理,这可能需要几秒钟到几小时之间的任何时间。但我不介意,只要客户愿意礼貌地等待。基于服务器的超时的问题是,如果它太低,客户端可能无法在它准备等待时得到它的答案,但如果它太高,我的服务器可能会继续进行大量计算(并处理额外的传入查询速度较慢)一劳永逸。

标签: perl timeout http-daemon


【解决方案1】:

通常,只要您正在处理数据(单线程),它就不会检查文件描述符,因此它不会检测到问题。我看到以下选项:

  • 不时检查process_query 内的$client 套接字是否可以使用IO::Select 或类似方法读取。可读的可能是客户端关闭了连接或发送了更多数据,例如HTTP 流水线。您可以尝试使用recvMSG_PEEK 检查是否有数据或eof(例如客户端关闭),但您将无法检测是否有更多数据后跟eof,因为您首先必须读取数据在你得到 eof 之前。
  • 如果您在 UNIX 上,您可以使用一个很少使用的功能:使用fcntl($client,F_SETOWN,$$),如果$client 套接字上有新事件,您可以让内核向您发送SIGIO 信号。但是我上次使用这个 Perl 时没有正确处理它,我不得不通过显式调用 fcntl-syscall:syscall(SYS_fcntl,fileno($client),F_SETOWN,$$); 来解决它。设置完成后,您可以像现在处理 ALRM 一样处理 IO 信号。

在任何情况下:来自客户端的 eof 仅表示客户端将不再写入(请求结束)。它可能仍然愿意读取您的数据(单向关闭)。您只有在发送数据并获得SIGPIPE 后才能知道客户端是否已关闭以供读取。没有办法,这就是带有 BSD 套接字的 TCP 的工作原理。

【讨论】:

  • 成功了!我选择了第二个选项,并且能够使用this answer. 使其工作它需要在F_SETOWN 之前设置O_NONBLOCKO_ASYNC 标志,并且$$ 必须强制使用0+$$ 进行数字上下文.谢谢!
猜你喜欢
  • 1970-01-01
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
  • 2012-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多