NAME
IO::Socket::Timeout - IO::Socket with read/write timeout
VERSION
version 0.17
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,
# 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";
}
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.
- WithSysTimeout
-
Defaults to 1. If set to a true value,
sysreadand <syswrite> functions will be subjects to the timeout as well. Otherwise they won't.
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.
METHODS
read_timeout
my $current_timeout = $socket->read_timeout();
$socket->read_timeout($new_timeout);
write_timeout
my $current_timeout = $socket->write_timeout();
$socket->write_timeout($new_timeout);
enable_timeout
$socket->enable_timeout;
disable_timeout
$socket->disable_timeout;
timeout_enabled
my $is_timeout_enabled = $socket->timeout_enabled();
$socket->timeout_enabled(0);
enable_sys_timeout
$socket->enable_sys_timeout;
disable_sys_timeout
$socket->disable_sys_timeout;
sys_timeout_enabled
my $is_sys_timeout_enabled = $socket->sys_timeout_enabled();
$socket->sys_timeout_enabled(0);
CHANGE SETTINGS AFTER CREATION
You can change the timeout settings of a socket after it has been instanciated.
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(:all);
# change read_timeout to 5 and write timeout to 1.5 sec
$socket->read_timeout(5)
$socket->write_timeout(1.5)
# actually disable the timeout for now
$socket->disable_timeout()
# when re-enabling it, timeouts value are restored
$socket->enable_timeout()
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');
SEE ALSO
Action::Retry, IO::Select, PerlIO::via::Timeout, Time::Out
THANKS
Thanks to Vincent Pitt, Christian Hansen and Toby Inkster for various help 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.