不论使用LWP还是IO::Socket,timeout参数都是一个古怪的问题,它要么不起作用,要么有很大的局限性,比如只有在目标地址能够连通,但 Socket无法建立的情况下才有效,如果完全连不上目标地址,程序就会阻塞,timeout设置的时间不起作用,这种情况一般叫做DNS解析错误,即使 是用ip连接也一样。
要实现完全可控制的timeout连接,常见的办法是使用alarm:

 
  
  1. #!/usr/bin/perl -w 
  2.  
  3. use strict; 
  4. use IO::Socket::INET; 
  5.  
  6. my $timeout = 5; 
  7.  
  8. eval 
  9.     local $SIG{ALRM} = sub { die 'Timed Out'; }; 
  10.     alarm $timeout; 
  11.     my $sock = IO::Socket::INET->new( 
  12.                      PeerAddr => 'somewhere'
  13.                      PeerPort => '80'
  14.                      Proto => 'tcp'
  15.                      ## timeout => , 
  16.     ); 
  17.     
  18.     $sock->autoflush(1); 
  19.  
  20.     print $sock "GET /  HTTP/1.0\n\n"
  21.     
  22.     undef $/; 
  23.     my $data = <$sock>; 
  24.     $/ = "\n"
  25.     
  26.     print "Resp: $data\n"
  27.     
  28.     alarm 0; 
  29. }; 
  30.  
  31. alarm 0; # race condition protection 
  32. print  "Error: timeout." if ( $@ && $@ =~ /Timed Out/ ); 
  33. print "Error: Eval corrupted: $@" if $@; 


但这在Win32中似乎没有效果,其实比较合理的做法是在Socket创建时不设定目标地址,然后将Socket设置为非阻塞模式,最后再连接地址:

 
  
  1. #!/usr/bin/perl 
  2.  
  3. use strict; 
  4. use IO::Socket::INET; 
  5. use IO::Select
  6. use IO::Handle; 
  7.  
  8. BEGIN 
  9.     if($^O eq 'MSWin32'
  10.     { 
  11.     eval '*EINPROGRESS = sub { 10036 };'
  12.     eval '*EWOULDBLOCK = sub { 10035 };'
  13.     eval '*F_GETFL     = sub {     0 };'
  14.     eval '*F_SETFL     = sub {     0 };'
  15.     *IO::Socket::blocking = sub 
  16.     { 
  17.         my ($self, $blocking) = @_; 
  18.         my $nonblocking = $blocking ? 0 : 1; 
  19.         ioctl($self, 0x8004667e, \$nonblocking); 
  20.     }; 
  21.     } 
  22.     else 
  23.     { 
  24.     require Errno; 
  25.     import  Errno qw(EWOULDBLOCK EINPROGRESS); 
  26.     } 
  27.  
  28. my $socket; 
  29. my $timeout = 5; 
  30.  
  31. if (!($socket = IO::Socket::INET->new( 
  32.          Proto    => "tcp"
  33.          Type     => SOCK_STREAM) )) 
  34.     print STDERR "Error creating socket: $@"
  35.  
  36. $socket->blocking(0); 
  37.  
  38. my $peeraddr; 
  39. if(my $inetaddr = inet_aton("somewhere")) 
  40.     $peeraddr = sockaddr_in(80, $inetaddr); 
  41. else 
  42.     print STDERR "Error resolving remote addr: $@"
  43.  
  44. $socket->connect($peeraddr); 
  45. $socket->autoflush(1); 
  46.  
  47. my $select = new IO::Select($socket); 
  48.  
  49. if($select->can_write($timeout)) 
  50.     my $req = "GET / HTTP/1.0\n\n"
  51.     print $socket $req; 
  52.  
  53.     if($select->can_read($timeout)) 
  54.     { 
  55.     my $resp; 
  56.     if($resp = scalar <$socket>) 
  57.     { 
  58.         chomp $resp; 
  59.         print "Resp: $resp\n"
  60.     } 
  61.     } 
  62.     else 
  63.     { 
  64.     print "Response timeout.\n"
  65.     } 
  66. else 
  67.     print "Connect timeout.\n"
  68.  
  69. close $socket; 
  70. exit; 


由 于在Win32中不能直接使用blocking(0),所以用ioctl进行设置,以上方法在Linux和Win32中都能正常工作,但如在Win32中 把IO::Socket::INET换成IO::Socket::SSL就不行了,后来我去perlmonks问了这个问题,但并没有得到解决:
http://www.perlmonks.org/?node_id=676887