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?

EDIT: Solution

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.


In reply to Making IO::Socket::UNIX client time out by kroach

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.