sunshine_august has asked for the wisdom of the Perl Monks concerning the following question:

hello, all monks:

I write a simple echo server and client script to test socket timeout. Originally, I think timeout in IO::Socket::INET means the sysread/syswrite will return a ETIMEOUT error if it can't read/write the message within the duration of the timeout. But from the result of my test, it seems that I am very wrong about this. Following is my simple code:

sever:
#!/usr/bin/perl use strict; use warnings; use IO::Socket::INET; my $listenSocket = IO::Socket::INET->new( 'LocalPort' => '12345', 'Listen' => SOMAXCONN, 'Reuse' => 1, 'Proto' => 'tcp', ) or die $@; my $conSocket = $listenSocket->accept; while ( defined $conSocket ) { my $rsp = q{}; $conSocket->sysread( $rsp, 20 ) or die $@; print "recv: $rsp\n"; $conSocket->syswrite( "hello, client!\n" ) or die $@; } ## end while ( defined $conSocket)
client:
#!/usr/bin/perl use strict; use warnings; use IO::Socket::INET; my $socket = IO::Socket::INET->new( 'Proto' => 'tcp', 'PeerAddr' => '172.16.249.232', 'PeerPort' => '12345', ) or die $@; $socket->timeout(2); while (1) { $socket->syswrite( "hello, server!\n") or die $!; my $rsp = q{}; $socket->sysread( $rsp, 20 ) or die $!; print "recv:$rsp\n"; sleep 1; } ## end while (1)

I run the server side script first, and then run the client side script, when the connection is established, and confirm that the two side can communicate with each other, then I disconnect the client side from the network, and wait for 2 seconds, but the client side didn't complain a ETIMEOUT error:(. So I think I misunderstood the meanning of the timeout in IO::Socket::INET.

Can anyone explain what does timeout means in socket? Thanks in advance.

Replies are listed 'Best First'.
Re: what does timeout mean in IO::Socket::INET ?
by Anonymous Monk on Dec 29, 2008 at 08:58 UTC
Re: what does timeout mean in IO::Socket::INET ?
by balakrishnan (Monk) on Dec 29, 2008 at 12:48 UTC
    actually those timeout handling part in IO::Socket::INET module has been commented out. So there is no purpose to use the timeout(). In Authen::Radius module, then had ETIMEOUT error for indicating that timed out waiting for packet.
        Yes, it used by IO::Socket. But note that it use it only in connect and accept. So if you want timeout in sysread you should set socket option or better use IO::Select.
Re: what does timeout mean in IO::Socket::INET ?
by gone2015 (Deacon) on Dec 29, 2008 at 20:34 UTC

    As you may have gathered, the Timeout IO::Socket::INET option is expected to apply only to connect and accept -- and some people doubt whether even that works on Win32... but more on that, below.

    For sysread and syswrite I know of three ways to introduce a time-out:

    1. use alarm and a signal handler. I've seen an eval wrapped around a read or write operation, with a signal handler that dies. A quick experiment suggests this is not necessary, an ALRM signal causes sysread to return with an EINTR "soft" error. However, alarm doesn't appear to work on Win32 -- I cannot find chapter and verse on this limitation, but I can say when I tried it (perl 5.10.0, ActivePerl Build 1002 283697) it did not work.

    2. socket options SO_RCVTIMEO and SO_SNDTIMEO seem to offer exactly what's required. Unfortunately the POSIX (1003.1, 2004) specification says "not all implementations allow this option to be set", which isn't encouraging -- life is complicated enough, already. When I tried it, Linux (2.6.27.7-53) rejected the attempt to $sock->sockopt(SO_RCVTIMEO, 10) :-(

    3. the final way is to use select, which may seem to be hard work, but is actually straighforward and has the advantage of working ! The following will read from an open socket $sock until it is closed by the far end, or nothing arrives for ten seconds, or some error occurs:

      my $select = IO::Select->new($sock) ; my $buffer = '' ; my $rc ; while (1) { $! = undef ; # no error, yet if ($select->can_read(10)) { $rc = sysread($sock, $buffer, 64*1024, length($buffer)); next if $rc ; # continue if not error and not "eof" last if defined($rc) ; # exit if "eof" } else { $rc = $! ? undef : 1 ; # $rc == undef if error, == 1 if time o +ut last if $rc ; # exit if time out } ; redo if $! == EAGAIN ; # Not really expected, even with non-bl +ocking redo if $! == EINTR ; # Signals ! last ; # exit on "hard" error } ; # Now: $rc == 0 => no error, == 1 => timed out, == undef => error
      and something similar should work for syswrite. Note that it is not necessary to set the socket non-blocking in order to use select, or for sysread to return with a partial result -- but it won't hurt to set the socket non-blocking.

    At some time in the past IO::Socket may have used alarm to implement time-out for connect/new and for accept. However, current implementation (v1.31) uses IO::Select, and works happily on Win32. (Looking at the ChangeLog, this appears to have been the case since v1.15, Sun 19 Jan 1997.)

      2. socket options SO_RCVTIMEO and SO_SNDTIMEO seem to offer exactly what's required. Unfortunately the POSIX (1003.1, 2004) specification says "not all implementations allow this option to be set", which isn't encouraging -- life is complicated enough, already. When I tried it, Linux (2.6.27.7-53) rejected the attempt to $sock->sockopt(SO_RCVTIMEO, 10) :-(
      Linux supports these options, but you should pass packed struct timeval as argument. This is not very portable way unfortunately. On my 64bit system (it's 2.6.27 too btw) it looks like this:
      my $timeo = pack("qq", 10, 0); $sock->sockopt(SO_RCVTIMEO, $timeo);
      On 32bit system you probably should use "ll" instead of "qq".