3

解决方案

正如@limulus 在我接受的答案中所报告的那样,这是Net::HTTPS6.00 版中的一个错误。始终警惕新的 .0 版本。这是该模块的错误版本和固定版本之间的相关差异:

D:\Opt\Perl512.32 :: diff lib\Net\HTTPS.pm site\lib\Net\HTTPS.pm
6c6
< $VERSION = "6.00";
---
> $VERSION = "6.02";
75,78c75,80
< # The underlying SSLeay classes fails to work if the socket is
< # placed in non-blocking mode.  This override of the blocking
< # method makes sure it stays the way it was created.
< sub blocking { }  # noop
---
> if ($SSL_SOCKET_CLASS eq "Net::SSL") {
>     # The underlying SSLeay classes fails to work if the socket is
>     # placed in non-blocking mode.  This override of the blocking
>     # method makes sure it stays the way it was created.
>     *blocking = sub { };
> }

原始问题

相关性:看到您的 HTTPS 客户端无限期阻塞是很烦人的,因为连接端点不可靠。

这个实验很容易在家里设置和重播。您只需要两件东西,一个用于捕获传入客户端的 tarpit 和一个 Perl 脚本。可以使用以下方式设置 tarpit netcat

nc -k -l localhost 9999 # on Linux, for multiple requests
nc -l -p 9999 localhost # on Cygwin, for one request only

然后,将脚本指向这个 tarpit:

use strict;
use LWP::UserAgent;
use HTTP::Request::Common;

print 'LWP::UserAgent::VERSION  ', $LWP::UserAgent::VERSION, "\n";
print 'IO::Socket::SSL::VERSION ', $IO::Socket::SSL::VERSION, "\n";

my $ua = LWP::UserAgent->new( timeout => 5, keep_alive => 1 );
$ua->ssl_opts( timeout => 5, Timeout => 5 ); # Yes - see note below!
my $rsp = $ua->request( GET 'https://localhost:9999' );
if ( $rsp->is_success ) {
  print $rsp->as_string;
} else {
  die $rsp->status_line;
}

这是要做什么?好吧,连接到NetCat打开的端口,然后……挂掉。无限期。至少在开发人员时间方面。我的意思是它可能会在十分钟或两个小时后超时,但我没有检查过;指定的超时时间不生效,在Linux上不生效,在Windows上也不生效(Win32,还没有检查Cygwin)。

使用的版本:

LWP::UserAgent::VERSION  6.02
IO::Socket::SSL::VERSION 1.44
# on Linux

LWP::UserAgent::VERSION  6.02
IO::Socket::SSL::VERSION 1.44
# on Win32

现在为timeoutTimeout参数。前者是LWP::UA的参数名称,后者是IO::Socket::SSL的名称,通过LWP::Protocol::https使用。(顺便说一句,为什么 metacpan HTTPS?嗯,至少它不是一个 tarpit。)我不知何故希望让这些参数一起传递:)

正如您所知,keep_alive与超时不起作用没有任何关系,我凭经验验证了这一点。:)

无论如何,在深入挖掘之前,有谁知道这里发生了什么以及如何使超时与 HTTPS 一起工作?很难相信我是第一个遇到这种情况的人。

4

3 回答 3

4

这是Net::HTTPS模块覆盖了 noopblocking方法的结果。IO::Socket升级到最新的Net::HTTP应该可以解决这个问题。

于 2012-04-20T07:31:11.930 回答
3

( timeoutand Timeout) 选项仅适用于连接——连接时将等待多少秒LWP::UserAgent——它们不适用于为整个事务设置超时。

您需要使用 Perl 的alarm处理$SIG{ALRM}程序来使整个事务超时。见perldoc -f alarmperlipc

local $SIG{ALRM} = sub { die "SSL timeout\n" };
my $ua = LWP::UserAgent->new( timeout => 5, keep_alive => 1 );
$ua->ssl_opts( timeout => 5, Timeout => 5 );

eval {
    alarm(10);
    my $rsp = $ua->request( GET 'https://localhost:9999' );
    if ( $rsp->is_success ) {
      print $rsp->as_string;
    } else {
      die $rsp->status_line;
    }
 };
 alarm(0);
 if ($@) {
     if ($@ =~ /SSL timeout/) {
         warn "request timed out";
     } else {
         die "error in request: $@";
     }
 }

(在 Linux 上测试。警报在 Windows/Cygwin 中可能会更坏一些

于 2012-02-22T19:10:21.993 回答
0

我在 PerlMonks 上问了这个问题,并得到了一个答案

底层 IO::Socket::INET 不支持 Win32 上的非阻塞套接字,因此 Win32 不支持非阻塞 IO::Socket::SSL,这也意味着超时不起作用(因为它们是基于非阻塞)。另见http://www.perlmonks.org/?node_id=378675

http://cpansearch.perl.org/src/SULLR/IO-Socket-SSL-1.60/README.Win32

指向的 PerlMonks 帖子来自 2004 年。不确定该信息是否仍然适用;毕竟,我已经看到超时在 Windows 上确实有效,只是不能通过 SSL。

于 2012-03-26T09:04:48.773 回答