Random_Walk has asked for the wisdom of the Perl Monks concerning the following question:
I am writing a little TCP/IP server to listen for heartbeats from remote machines and raise an alert if one is missed. To keep things simple rather than spawning child processes to handle connections I start a thread that comunicates through a Thread::Queue. Is this safe to do with IO:Socket ? My code follows with a small script to send the heartbeat at the end. Comments on the code also welcome
And here is a short script to send heartbeats#!/usr/bin/perl use strict; use warnings; use IO::Socket; use threads; use Thread::Queue; #get the port to bind to or default to 8000 my $port = $ARGV[0] || 8000; # a hash to record client machines and thread queue for internal comun +ication my %clients; my $queue = Thread::Queue -> new; my $monitor = threads->create ("monitor", $queue); #ignore child processes to prevent zombies $SIG{CHLD} = 'IGNORE'; #create the listen socket my $listen_socket = IO::Socket::INET->new(LocalPort => $port, Listen => 10, Proto => 'tcp', Reuse => 1); #make sure we are bound to the port die "Cant't create a listening socket: $@" unless $listen_socket; warn "Server ready. Waiting for connections on $port ... \n"; #wait for connections at the accept call while (my $connection = $listen_socket->accept) { # spawn a thread to handle the connection my $child = threads->create ("read_data", $queue, $connection); } sub read_data { # accept data from the socket and put it on the queue my ($queue, $socket) = @_; while (<$socket>) { print "listener got: $_"; $queue -> enqueue(time." $_"); } } sub monitor { my $queue = shift; while (1) { while ($queue -> pending) { my $data = $queue -> dequeue; print "monitor got: $data"; $data =~ /(\d+) Heartbeat from (\S+) next one in (\d+) min +utes/; my $time = $1; my $client = $2; my $cycle = $3; if (defined $clients{$client} and $clients{$client} -> [0] + eq 'NAK') { print "$client sent a beat again\n"; } $clients{$client} = [ 'OK', $time + $cycle * 60 ]; } for my $client (keys %clients) { next if $clients{$client}->[0] eq 'NAK'; next if $clients{$client}->[1] > time; print "$client missed a heartbeat, expected at $clients{$c +lient}->[1], now it is ".time."\n"; $clients{$client}->[0] = 'NAK'; } sleep 30; } }
#!/usr/bin/perl use strict; use warnings; use IO::Socket; chomp(my $hostname = `hostname`); $hostname =~ s/\..*//; my $me = $ARGV[0] || $hostname; my $cycle_time = $ARGV[1] || 5; my $port = $ARGV[2] || 8000; my $ecg = 'rtmr'; while (1) { print "sending heartbeat\n"; my $socket = IO::Socket::INET->new(PeerAddr => $ecg, PeerPort => $port, Proto => "tcp", Type => SOCK_STREAM) or die "Couldn't connect to $ecg:$port : $@\n"; print "Heartbeat from $me next one in $cycle_time minutes\n"; print $socket "Heartbeat from $me next one in $cycle_time minutes\ +n"; close($socket); print "zzzzz......\n"; sleep $cycle_time * 60; }
Thanks in advance,
R.
|
|---|