I have a simple TCP server and client written using AnyEvent::Handle
leveraging tcp_connect
and tcp_server
. The client connects to the server and sends the string Test Message
every 5 seconds.
This works without issue if the server is reachable, however, if the server is unavailable when the client launches, or becomes unavailable, the client script never tries to reconnect.
I'd like it to try and reconnect if the connection handle is not available (destroyed?). If unavailable, do things (print status message perhaps), but try and reconnect every 5 seconds would be the ideal outcome.
I'm not sure how to do that. I've pared down my client and server code to the following.
Client
#!/usr/bin/perl
use strict;
use warnings;
use AnyEvent;
use AnyEvent::Handle;
use AnyEvent::Socket;
use Compress::Zlib;
my @bulk;
# Start Timer
my $timer = AnyEvent->timer(
after => 5,
interval => 5,
cb => sub {
push( @bulk, "Test message" );
flush( \@bulk );
undef @bulk;
} );
my $host = '127.0.0.1';
my $port = 9999;
my $conn_cv = AnyEvent->condvar;
my $conn_hdl;
$conn_hdl = AnyEvent::Handle->new(
connect => [$host, $port],
keepalive => 1,
on_connect_error => sub {
print "Could not connect: $_[1]\n";
$conn_hdl->destroy;
#$conn_cv->send;
},
on_error => sub {
my ( $out_hdl, $fatal, $msg ) = @_;
AE::log error => $msg;
$conn_hdl->destroy;
#$conn_cv->send;
},
on_read => sub {
my ( $self ) = @_;
$self->unshift_read(
line => sub {
my ( $hdl, $data ) = @_;
print $data. "\n";
} );
} );
$conn_cv->recv;
# Flush array of events
sub flush {
my ( $bulk ) = @_;
return 0 if scalar @{$bulk} == 0;
my $output = join( ",", @{$bulk} );
$output = compress( $output );
my $l = pack( "N", length( $output ) );
$output = $l . $output;
$conn_hdl->push_write( $output );
}
Server
#!/usr/bin/perl
use strict;
use warnings;
use AnyEvent;
use AnyEvent::Handle;
use AnyEvent::Socket;
use Compress::Zlib;
my %holding;
my $host = '127.0.0.1';
my $port = 9999;
my %connections;
# Start Timer
my $timer = AnyEvent->timer(
after => 5,
interval => 5,
cb => sub {
print "Number of connected hosts: ";
print scalar keys %connections;
print "\n";
foreach my $k ( keys %connections ) {
delete $connections{$k} if $connections{$k}->destroyed;
}
} );
my $server_cv = AnyEvent->condvar;
my $server = tcp_server(
$host, $port,
sub {
my ( $fh, $h, $p ) = @_;
my $handle;
$handle = AnyEvent::Handle->new(
fh => $fh,
poll => 'r',
keepalive => 1,
on_read => sub {
my ( $self ) = @_;
# Get Length Header
$self->unshift_read(
chunk => 4,
sub {
my $len = unpack( "N", $_[1] );
# Get Data
$self->unshift_read(
chunk => $len,
sub {
my $data = $_[1];
$data = uncompress( $data );
print $data. "\n";
} );
} );
},
on_eof => sub {
my ( $hdl ) = @_;
$hdl->destroy();
},
on_error => sub {
my ( $hdl ) = @_;
$hdl->destroy();
},
);
$connections{ $h . ':' . $p } = $handle; # keep it alive.
} );
$server_cv->recv;
You can use the following:
I'm pretty sure it's free of memory leaks (unlike your code). You'd use it as follows: