2010-08-25 7 views

risposta

17

Se si controlla il codice vedrete (ho copiato dal mio Ubuntu 10.04):

 my $timeout = ${*$sock}{'io_socket_timeout'}; 
#  my $before = time() if $timeout; 

     undef [email protected]; 
     if ($sock->connect(pack_sockaddr_in($rport, $raddr))) { 
#   ${*$sock}{'io_socket_timeout'} = $timeout; 
      return $sock; 
     } 

     return _error($sock, $!, [email protected] || "Timeout") 
      unless @raddr; 

#  if ($timeout) { 
#   my $new_timeout = $timeout - (time() - $before); 
#   return _error($sock, 
#       (exists(&Errno::ETIMEDOUT) ? Errno::ETIMEDOUT() : $EINVAL), 
#       "Timeout") if $new_timeout <= 0; 
#   ${*$sock}{'io_socket_timeout'} = $new_timeout; 
#  } 

A quanto pare la roba Timeout è commentato in modo che expleins perché è ignorato.

Ho trovato uno post datato 2003 in cui è stato discusso. Un suggerimento (in basso) è stato quello di aprire il socket in un blocco eval che viene terminato da un segnale di allarme:

eval { 
    local $SIG{ALRM} = sub { die 'Timed Out'; }; 
    alarm 3; 
    my $sock = IO::Socket::INET->new( 
    PeerAddr => inet_ntoa(gethostbyname($host)), 
    PeerPort => 'whois', 
    Proto => 'tcp', 
    ## timeout => , 
); 
    $sock->autoflush; 
    print $sock "$qry\015\012"; 
    undef $/; $data = <$sock>; $/ = "\n"; 
    alarm 0; 
}; 
alarm 0; # race condition protection 
return "Error: timeout." if ([email protected] && [email protected] =~ /Timed Out/); 
return "Error: Eval corrupted: [email protected]" if [email protected]; 

Non molto elegante, ma se funziona ...

Facciamo verificare con un lento server e client impaziente:

# Impatient Client 
use IO::Socket::INET; 

$sock = new IO::Socket::INET(
    PeerAddr => "localhost", 
    PeerPort => "10007", 
    Proto => 'tcp', 
    Timeout => 2, 
    ); 

print <$sock>; 

close($sock); 


# SlowServer 
use IO::Socket::INET; 

$sock = new IO::Socket::INET(
    LocalAddr => "localhost", 
    LocalPort => "10007", 
    Proto => 'tcp', 
    Listen => 1, 
    Reuse => 1, 
    ); 

$newsock = $sock->accept(); 
sleep 5; 

#while (<$newsock>) { 
# print $_; 
#} 
print $newsock "Some Stuff"; 
close($newsock); 
close($sock); 

se corriamo questo:

[email protected]:~/playpen$ perl server.pl& 
[1] 9130 
[email protected]:~/playpen$ time perl test.pl 
Some Stuff[1]+ Done     perl server.pl 

real 0m5.039s 
user 0m0.050s 
sys  0m0.030s 

Così Igno res il timeout di 2 secondi e viene eseguito per i 5 secondi completi.

Ora l'altro client impazienti:

use IO::Socket::INET; 
eval { 
    local $SIG{ALRM} = sub { die 'Timed Out'; }; 
    alarm 2; 
    $sock = new IO::Socket::INET(
    PeerAddr => "localhost", 
    PeerPort => "10007", 
    Proto => 'tcp', 
    Timeout => 2, 
    ); 

    print <$sock>; 

    close($sock); 
    alarm 0; 
}; 
alarm 0; # race condition protection 
print "Error: timeout." if ([email protected] && [email protected] =~ /Timed Out/); 
print "Error: Eval corrupted: [email protected]" if [email protected]; 

~

ed eseguirlo:

[email protected]:~/playpen$ perl server.pl& 
[1] 9175 
[email protected]:~/playpen$ time perl test2.pl 
Error: timeout.Error: Eval corrupted: Timed Out at test2.pl line 3. 

real 0m2.040s 
user 0m0.020s 
sys   0m0.010s 

Sì, questo timeout dopo 2 secondi come previsto.

+1

L'attributo 'Timeout' non viene ignorato, ma viene utilizzato nel costruttore di' IO :: Socket', non 'IO :: Socket :: INET'. Questa è una buona soluzione, tuttavia, e qualcosa di simile è necessario per Windows. – mob

+0

È vero, ma il suo uso è commentato nel sotto configure di IO :: Socket :: INET. AFAICS è impostato, ma mai usato in :: INET. –

+0

Grazie, ha funzionato per me. Ma, perché quella parte è commentata nella fonte? – code2be

Problemi correlati