#!/usr/bin/perl use 5.010; use strict; use warnings; use IO::Socket; my $INTERVAL = 10; my $MAX_BUFSIZE = 512; my $NO_CONTACT = 0; my $SENDING = 1; my $LOST_CONTACT = 2; my $server = '192.168.0.1'; my @server_ports = (8020, 8019, 8008, 8003); my @sockets = map { my $socket = IO::Socket::INET::->new( LocalPort => $_, LocalAddr => $server, Proto => 'udp', ) or die $!; $socket; } @server_ports; my @states = ($NO_CONTACT) x @sockets; my @heartbeats = (0) x @sockets; my @counts = (0) x @sockets; my $Rbits = ""; my $Ebits = ""; vec($Rbits, fileno($_), 1) = 1 for @sockets; vec($Ebits, fileno($_), 1) = 1 for @sockets; while (1) { select(my $rbits = $Rbits, undef, my $ebits = $Ebits, 1); for (my $i = 0; $i < @sockets; $i ++) { my $socket = $sockets[$i]; my $fileno = fileno($socket); my $state = $states[$i]; my $heartbeat = $heartbeats[$i]; if (vec($ebits, $fileno, 1)) { say "Got an error on channel $i. I'm out of here"; exit 1; } if (vec($rbits, $fileno, 1)) { my $sender = $socket->recv(my $buffer, $MAX_BUFSIZE); if (length $buffer) { my ($port, $remote) = sockaddr_in($sender); $remote = inet_ntoa($remote); say "Got HB from $remote:$port"; $heartbeat = $heartbeats[$i] = time; if ($state == $NO_CONTACT) { # # Upgrade the socket now we know the remote # vec($Rbits, fileno($socket), 1) = 0; vec($Ebits, fileno($socket), 1) = 0; undef $sockets[$i]; undef $socket; $socket = $sockets[$i] = IO::Socket::INET::->new( LocalPort => $server_ports[$i], LocalAddr => $server, PeerAddr => $remote, PeerPort => $port, Proto => 'udp', ) or die $!; vec($Rbits, fileno($socket), 1) = 1; vec($Ebits, fileno($socket), 1) = 1; $state = $states[$i] = $SENDING; } } } # # Out of time? # if ($state == $SENDING && $heartbeat + $INTERVAL < time) { say "Channel $i is dead. Bye!"; exit 1; } # # Send data? # if ($state == $SENDING) { foreach (1 .. int rand 10) { my $count = ++$counts[$i]; say "Send packet $count on channel $i"; $socket->send($count); } } } } __END__