IO::Socket::Timeout: socket timeout made easy

Without network operations, running a website for booking accommodation online would be nearly impossible. Network operations can be anything from simple actions like talking to a browser with a user at the other end, to providing an API for our affiliates, or even writing the internal services that help maintain our systems.

dams
dams
Feb 26, 2015 · 11 min read
Image for post
Image for post

What is a network socket

# example 1
my $socket = IO::Socket::INET->new('google.com:80');
print {$socket} "GET / \n";
my $html = join '', <$socket>;
# example 2
my $socket = IO::Socket::INET->new(
PeerHost => 'www.booking.com',
PeerPort => 80,
);

$socket->print("GET / \n");
my $html = join '', $socket->getlines();

Why sockets timeouts are important

Connection timeout

my $socket = IO::Socket::INET->new(
PeerHost => '127.0.0.1',
PeerPort => 80,
Timeout => 3,
);

Read/Write timeouts via setsockopt

my $seconds  = int($timeout);
my $useconds = int( 1_000_000 * ( $timeout - $seconds ) );
my $timeout = pack( 'l!l!', $seconds, $useconds );
$socket->setsockopt( SOL_SOCKET, SO_RCVTIMEO, $timeout )
# then use $socket as usual

Read/Write timeouts via select

sub _can_read {
my ( $file_desc, $timeout ) = @_;
vec( my $fdset = '', $file_desc, 1 ) = 1;
my $nfound = select( $fdset, undef, undef, $timeout );
}

Using an external library

my $handle = AnyEvent::Handle->new (
connect => [ $host, $port ],
on_prepare => sub { 0.5 },
# ...
);

$handle->on_timeout( sub { say 'timeout occurred' } );
$handle->timeout(0.01);

Provide a nice API

my $socket = IO::Socket::INET->new( ... );
print {$socket} 'something';
my $socket = IO::Socket::INET->new( ... );

# set timeouts
$socket->read_timeout(0.5);

# use the socket as before
print {$socket} 'something';

# later, get the timeout value
my $timeout = $socket->read_timeout();

when using setsockopt

when using select

PerlIO layers

open my $fh, 'filename';
# for direct binary non-buffered access
binmode $fh, ':raw';
# specify that the file is in utf8, and enforce validation
binmode $fh, ':encoding(UTF-8)';
my $line = <$fh>;
binmode $fh, ':via(MyOwnLayer)';

Implementing a timeout PerlIO layer

package PerlIO::via::Timeout;
sub READ {
my ( $self, $buf, $len, $fh ) = @_;
my $fd = fileno($fh);

# we use the same can_read as previously
can_read( $fd, $timeout )
or return 0;

return sysread( $fh, $buf, $len, 0 );
}
use PerlIO::via::Timeout;
open my $fh, '<:via(Timeout)', 'foo.html';
my $line = <$fh>;
if ( $line == undef && 0+$! == ETIMEDOUT ) {
# timed out reading
...
} else {
# we read one line fast enough, success!
...
}

Add a properties to a Handle using InsideOut OO

my %fd_properties;

sub PUSHED {
my ( $class, $mode, $fh ) = @_;
$fd_properties{ fileno($fh) } = { read_timeout => 0.5 };
# ...
}

Implement the API

wrap it up

# 1. Creates a socket as usual
my $socket = IO::Socket::INET->new( ... );

# 2. Enable read and write timeouts on the socket
IO::Socket::Timeout->enable_timeouts_on($socket);

# 3. Setup the timeouts
$socket->read_timeout(0.5);
$socket->write_timeout(0.5);

# 4. Use the socket as usual
my $data = <$socket>;

# 5. Profit!

Conclusion


Booking.com Development

Software development at Booking.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store