正如@limulus在我接受的答案中所报告的,这是Net::HTTPS
版本6.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脚本。可以使用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
现在提供timeout
和Timeout
个参数。前者是LWP::UA的参数名称,后者是IO::Socket::SSL的名称,通过LWP::Protocol::https使用。 (顺便说一句,为什么metacpan HTTPS?好吧,至少它不是一个tarpit。)我不知何故希望传递这些参数:)
您知道,keep_alive
与超时不起作用没有任何关系,我根据经验验证了这一点。 :)
无论如何,在深入挖掘之前,是否有人知道这里发生了什么以及如何使用HTTPS进行超时?很难相信我是第一个遇到这种情况的人。
答案 0 :(得分:4)
这是Net::HTTPS
模块使用noop覆盖blocking
IO::Socket
方法的结果。升级到latest Net::HTTP
package应解决此问题。
答案 1 :(得分:2)
timeout
(和Timeout
)选项仅适用于连接 - LWP::UserAgent
在连接时等待的秒数 - 它们不用于在整个事务中设置超时
您希望使用Perl的alarm
和$SIG{ALRM}
处理程序来超时整个事务。请参阅perldoc -f alarm
或perlipc
。
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上测试。Alarms can be a bit more cantankerous in Windows/Cygwin)
答案 2 :(得分:0)
I asked this question on PerlMonks和received an answer表示:
底层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。