NAME

IO::Socket::Timeout - IO::Socket with read/write timeout

VERSION

version 0.14

SYNOPSIS

use IO::Socket::With::Timeout;

# creates a IO::Socket::INET::With::Timeout object
my $socket = IO::Socket::INET->new::with::timeout( Timeout => 2,
                                                   ReadTimeout => 0.5,
                                                   # other standard arguments );

my $socket = IO::Socket::UNIX->new::with::timeout( Timeout => 2,
                                                   ReadTimeout => 0.5,
                                                   WriteTimeout => 0.5,
                                                   # other standard arguments );

my $socket = IO::Socket::INET->new::with::timeout( Timeout => 2,
                                                   ReadWriteTimeout => 0.5,
                                                   TimeoutStrategy => 'Alarm',
                                                   # other standard arguments );

my $socket = IO::Socket::INET->new::with::timeout( Timeout => 2,
                                                   ReadWriteTimeout => 0.5,
                                                   TimeoutStrategy => '+My::Own::Strategy',
                                                   # other standard arguments );

# When using the socket:
use Errno qw(ETIMEDOUT);
print $socket $request;
my $response = <$socket>;
if (!defined $response && 0+$! == ETIMEDOUT) {
  die "timeout reading on the socket";
}

# You can change the default strategy that will be used, if possible.
use IO::Socket::With::Timeout default_strategy => Select;

DESCRIPTION

IO::Socket provides a way to set a timeout on the socket, but the timeout will be used only for connection, not for reading / writing operations.

This module provides a way to set a timeout on read / write operations on an IO::Socket instance, or any IO::Socket::* modules, like IO::Socket::INET.

CONSTRUCTORS

new::with::timeout

To be able to work with any class that is or inherits from IO::Socket, the interface of this module is a bit unusual.

IO::Socket::INET-new::with::timeout(...)> will return an instance of IO::Socket::INET, as if it had been called with IO::Socket::INET-new(...)>. However, it'll apply some mechanism on the resulting socket object so that it times out on read, write, or both.

The way the socket will timeout ( on connection, read, write, how long), can be specified with these parameters:

Timeout

This is the default parameter that already exists in IO::Socket. If set to a value, the socket will timeout at connection time.

ReadTimeout

If set to a value, the socket will timeout on reads. Value is in seconds, floats accepted.

WriteTimeout

If set to a value, the socket will timeout on writes. Value is in seconds, floats accepted.

ReadWriteTimeout

If set to a value, the socket will timeout on reads and writes. Value is in seconds, floats accepted. If set, this option superseeds ReadTimeout and WriteTimeout.

TimeoutStrategy

Used to specify the timeout implementation used. The value should be a module name. If it doesn't start with +, the value will be prepended with PerlIO::via::Timeout::Strategy::. If it does start with +, the value is expected to be the fullname of a module. The default value is 'SetSockOpt' unless the detected Operating System is NetBSD or Solaris, in which case it'll use SelectWithReset instead. See PerlIO::via::Timeout::Strategy::SetSockOpt for instance.

To get a list of available strategy, see below ("AVAILABLE STRATEGIES").

socketpair::with::timeout

There is an other way to create sockets from scratch, via socketpair. As for the new constructor, this module provides its counterpart with timeout feature.

IO::Socket::INET-socketpair::with::timeout(...)> will return two instances of IO::Socket::INET, as if it had been called with IO::Socket::INET-socketpair(...)>. However, it'll apply some mechanism on the resulting socket object so that it times out on read, write, or both.

FINE-TUNING

If you need to alter the behavior of the socket after it has been created, you can access its strategy and fiddle with it, using PerlIO::via::Timeout.

use IO::Socket::With::Timeout;
# create a socket with read timeout
my $socket = IO::Socket::INET->new::with::timeout( Timeout => 2,
                                                   ReadTimeout => 0.5,
                                                   # other standard arguments );
use PerlIO::via::Timeout qw(timeout_strategy);
# use PerlIO::via::Timeout to retrieve the strategy
my stratefy = timeout_strategy($sock);
# change read_timeout to 5 and write timeout to 1.5 sec
$strategy->read_timeout(5)
$strategy->write_timeout(1.5)
# actually disable the timeout for now
$strategy->disable_timeout()
# when re-enabling it, timeouts value are restored
$strategy->enable_timeout()

See PerlIO::via::Timeout for more details

WHEN TIMEOUT IS HIT

When a timeout (read, write) is hit on the socket, the function trying to be performed will return undef, and $! will be set to ETIMEOUT.

The socket will be marked as invalid internally, and any subsequential use of it will return undef, and $! will be set to ECONNRESET.

Why invalid the socket ? If you read a socket, waiting for message A, and hit a timeout, if you then reuse the socket to read a message B, you might receive the answer A instead. There is no way to properly discard the first message, because the sender mught not be reachable (that's probably why you got a timeout in the first place). So after a timeout failure, it's important that you recreate the socket.

You can import ETIMEOUT and ECONNRESET by using POSIX:

use Errno qw(ETIMEDOUT ECONNRESET);

IF YOU NEED TO RETRY

If you want to implement a try / wait / retry mechanism, I recommend using a third-party module, like Action::Retry. Something like this:

my $socket;

my $answer;
my $action = Action::Retry->new(
  attempt_code => sub {
      # (re-)create the socket if needed
      $socket && ! $socket->error
        or $socket = IO::Socket->new::with::timeout(ReadTimeout => 0.5);
      # send the request, read the answer
      $socket->print($_[0]);
      defined($answer = $socket->getline) or die $!;
      $answer;
  },
  on_failure_code => sub { die 'aborting, to many retries' },
);

my $reply = $action->run('GET mykey');

AVAILABLE STRATEGIES

Here is a list of strategies to be used. You can create your own (see below).

SetSockOpt

Doesn't work on Solaris and NetBSD.

This strategy sets appropriate read / write options on the socket, to have a proper timeout. This is probably the most efficient and precise way of setting up a timeout.

It makes sure the socket can't be used once the timeout has been hit, by returning undef and setting $! to ECONNRESET.

See PerlIO::via::Timeout::Strategy::SetSockOpt.

SelectWithReset

Uses select.

It makes sure the socket can't be used once the timeout has been hit, by returning undef and setting $! to ECONNRESET.

See PerlIO::via::Timeout::Strategy::SelectWithReset.

AlarmWithReset

Doesn't work on Win32. Uses Time::Out (which uses alarm internally).

It makes sure the socket can't be used once the timeout has been hit, by returning undef and setting $! to ECONNRESET.

See PerlIO::via::Timeout::Strategy::AlarmWithReset.

DEFAULT STRATEGY

When nothing is specified, IO::Socket::Timeout will use the SetSockOpt strategy by default, unless the detected Operating System is NetBSD or Solaris. In which case it'll use SelectWithReset instead.

you can override the default strategy being used using one of these ways:

import option
# this will setup the Alarm strategy by default
use IO::Socket::Timeout default_strategy => 'Alarm';

# same, but at runtime
require IO::Socket::Timeout;
IO::Socket::Timeout->import(default_strategy => 'Alarm');

# you can also use your own strategy as default
use IO::Socket::Timeout default_strategy => '+My::Strategie';
configuration variable
$IO::Socket::Timeout::DEFAULT_STRATEGY = 'Alarm';

CREATE YOUR OWN STRATEGY

SEE ALSO

Action::Retry, IO::Select, PerlIO::via::Timeout, Time::Out

THANKS

The author would like to thank Toby Inkster, Vincent Pitt for various helps and useful remarks.

AUTHOR

Damien "dams" Krotkine

COPYRIGHT AND LICENSE

This software is copyright (c) 2013 by Damien "dams" Krotkine.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.