kroach has asked for the wisdom of the Perl Monks concerning the following question:
I'm trying to make a IO::Socket::UNIX client connection time out after some time if the server is too slow to respond. I tried using the Timeout argument from IO::Socket but it doesn't appear to work in this case. Here is a server/client example:
#!/usr/bin/perl use strict; use warnings; use IO::Socket::UNIX; use constant SOCKET => 'test_socket.sock'; my $mode = shift or die "Specify a mode\n"; if ($mode eq 'server') { my $server = IO::Socket::UNIX->new( Type => SOCK_STREAM, Local => SOCKET, Listen => 1, ) or die $!; while (my $conn = $server->accept()) { sleep 5; my $name = <$conn>; print {$conn} "Hello $name"; close $conn; } } elsif ($mode eq 'client') { my $client = IO::Socket::UNIX->new( Type => SOCK_STREAM, Peer => SOCKET, Timeout => 2, ) or die $!; print {$client} 'John', "\n"; print "Got reponse: ", scalar <$client>; close $client; } else { die "Unsupported mode: $mode\n"; }
The client is set to time out after 2 seconds and the server to take at least 5 seconds to respond. I expected the client to stop after 2 seconds, however it just reads the response after 5 seconds as if the Timeout was completely ignored. Am I doing something wrong?
There is a solution using alarm() in perlipc which works for any kind of blocking code:
my $ALARM_EXCEPTION = "alarm clock restart"; eval { local $SIG{ALRM} = sub { die $ALARM_EXCEPTION }; alarm 10; flock(FH, 2) # blocking write lock || die "cannot flock: $!"; alarm 0; }; if ($@ && $@ !~ quotemeta($ALARM_EXCEPTION)) { die }
However, there is probably a cleaner way to do it. Any ideas? What's the recommended way to make a socket client timeout?
It's possible to use setsockopt to set the read timeout:
use POSIX qw[ ETIMEDOUT EWOULDBLOCK ]; use Socket qw[ SOL_SOCKET SO_RCVTIMEO ]; my $client = IO::Socket::UNIX->new( Type => SOCK_STREAM, Peer => SOCKET, ) or die $!; my $timeval = pack 'l!l!, 2, # seconds 0; # microseconds $socket->setsockopt(SOL_SOCKET, SO_RCVTIMEO, $timeval) or die $!; print {$client} "John", "\n"; my $response = <$client>; die 'Timeout' if !$response and $! == ETIMEDOUT || $! == EWOULDBLOCK; ...
In order to set a write timeout, replace SO_RCVTIMEO with SO_SNDTIMEO. This is exactly what IO::Socket::Timeout does, I'm leaving a pure solution here for educational purposes, in case someone stumbles upon this thread in the future.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Making IO::Socket::UNIX client time out
by shadowsong (Pilgrim) on Oct 03, 2019 at 00:03 UTC | |
|
Re: Making IO::Socket::UNIX client time out
by Fletch (Bishop) on Oct 02, 2019 at 13:13 UTC | |
by kroach (Pilgrim) on Oct 02, 2019 at 13:25 UTC | |
|
Re: Making IO::Socket::UNIX client time out
by Don Coyote (Hermit) on Oct 02, 2019 at 13:17 UTC | |
by kroach (Pilgrim) on Oct 02, 2019 at 13:28 UTC |