Perl: Como llegar IO :: Socket :: INET tiempo de espera después de X segundos?
-
01-10-2019 - |
Pregunta
Estoy intentando conectar con un poco de anfitrión, utilizando el puerto no válido, y quiero conseguir tiempo de espera después de X segundos. ¿Cómo hacer eso?
Mi código:
$sock = new IO::Socket::INET(
PeerAddr => $_[0],
PeerPort => $_[1],
Proto => 'tcp',
Timeout => 2
);
Solución
Si marca el código verás (lo copié de mi Ubuntu 10.04):
my $timeout = ${*$sock}{'io_socket_timeout'};
# my $before = time() if $timeout;
undef $@;
if ($sock->connect(pack_sockaddr_in($rport, $raddr))) {
# ${*$sock}{'io_socket_timeout'} = $timeout;
return $sock;
}
return _error($sock, $!, $@ || "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;
# }
Al parecer, el tiempo de espera de la materia está comentado de manera que expleins por lo que se ignora.
posterior que data de 2003, donde se discutió este. Una sugerencia (en la parte inferior) fue abrir la toma en un bloque eval que se termina por una señal de alarma:
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 ( $@ && $@ =~ /Timed Out/ );
return "Error: Eval corrupted: $@" if $@;
No es muy elegante, pero si funciona ...
Vamos a verificar con un servidor y cliente impaciente lenta:
# 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);
si corremos esto:
pti@pti-laptop:~/playpen$ perl server.pl&
[1] 9130
pti@pti-laptop:~/playpen$ time perl test.pl
Some Stuff[1]+ Done perl server.pl
real 0m5.039s
user 0m0.050s
sys 0m0.030s
Así que no tiene en cuenta los 2 segundos de tiempo y se ejecuta por completo los 5 segundos.
Ahora el otro cliente impaciente:
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 ( $@ && $@ =~ /Timed Out/ );
print "Error: Eval corrupted: $@" if $@;
~
y ejecutarlo:
pti@pti-laptop:~/playpen$ perl server.pl&
[1] 9175
pti@pti-laptop:~/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í, este tiempo de espera después de 2 segundos como se esperaba.