#!/usr/local/bin/perl -w use strict; use warnings; use IO::Socket::INET; use IO::Handle; use IO::Select; require POSIX; # provides WNOHANG # Set up a signal handler. # This prevents child processes from becoming zombies. # The subroutine is defined further below. $SIG{CHLD} = \&reap_kids; my $IsParent = 1; my $ListenPort = 5000; my $PPID = $$; sub StartServer { (my $Port) = @_; print "StartServer($Port) \n"; my %data; my %nextpass; my $bufs =""; my $tbufs; my $TempSessionID = "12345"; $0="UE_ServerListen_$TempSessionID\_Port_$Port"; # Rename process my $socket = new IO::Socket::INET ( LocalHost => '127.0.0.1', LocalPort => $Port, Proto => 'tcp', Listen => $Port, Blocking => 0, Reuse => 1 ) or die "ERROR in Socket Creation : $!\n"; # Bound to 127.0.0.1:$Port my $select = IO::Select->new($socket) or die "IO::Select $!"; # server waiting for client connection on port $Port print "Server started listen on port $Port \n"; my $IsRunning = 1; while($IsRunning) { # Fix For UEC process stays alive in the BG my $exists = kill 0, $PPID; print "Parent is dead exiting...\n" if (!$exists); $data{'Sys_Status'} = 0 if (!$exists); $IsRunning = 0 if (!$exists); my @ready_clients = $select->can_read(0); foreach my $fh (@ready_clients) { if($fh == $socket) { # New client $fh (total clients: (($select->count)-1) my $new = $socket->accept(); $select->add($new); } } @ready_clients = $select->can_read(0); foreach my $fh (@ready_clients) { if($fh != $socket) { $fh->recv(my $tmpbufs,1024); if ($tmpbufs) { my $bufs=""; my $tbufs=""; $bufs=$nextpass{$fh} if $nextpass{$fh}; if (substr($tmpbufs, -1) ne "\n") { for (my $x=length($tmpbufs);$x>=1;$x--) { if (substr($tmpbufs, $x,1) eq "\n") { $tbufs=substr($tmpbufs,0, $x); $nextpass{$fh}=substr($tmpbufs,$x+1); last ; } } $bufs.=$tbufs; } else { my $tmp = $nextpass{$fh}; if ((defined($tmp)) && ($tmp ne '')) { $bufs= $nextpass{$fh}.$tmpbufs; $nextpass{$fh}=""; } else { $bufs= $tmpbufs; $nextpass{$fh}=""; } } chomp($bufs); foreach my $buf ((split(/\n/,$bufs))) { chomp($buf); (my $command,my $key,my $value)=split(/\|/,$buf); if ($command =~ /Die/) { $IsRunning = 0; exit; } elsif ($command =~ /w/) { $data{$key}=$value;} elsif ($command =~ /r/) { print $fh "$data{$key}\n"; } elsif ($command =~ /m/) { delete $data{$key}; } elsif ($command =~ /e/) { my $ResVal = exists($data{$key}); print $fh "$ResVal\n"; } elsif ($command =~ /s/) { printTS($value . "\n",-1,0.000,$key,1); } elsif ($command =~ /k/) { my $count=0; foreach my $key (keys %data) { print $fh "$key\n"; } print $fh "EOT\n"; } else { print "BAD: $buf \n $bufs|"; } } } else { # Client disconnected $select->remove($fh); # Connection Closed: $fh close($fh); # Total connected clients => (($select->count)-1) } } } select(undef,undef,undef, .1); } $socket->close(); } sub ConnectToServer { (my $host ,my $Port ,my $cmd_timeout)= @_; print "ConnectToServer($host ,$Port ,$cmd_timeout) \n"; alarm ($cmd_timeout); my $t_recv = new IO::Socket::INET ( PeerHost => $host, PeerPort => $Port, TimeOut => $cmd_timeout, Blocking => 1, Proto => 'tcp',) or print "Unable make connection\n"; alarm 0; return $t_recv; } sub KillServer { (my $SocketHndl) = @_; print "KillServer($SocketHndl)\n"; if ((defined($SocketHndl)) && ($SocketHndl != 0)) { print $SocketHndl "Die\n"; } } sub WriteValueToDB { (my $Value, my $DbHndl, my $HashKey) = @_; print "WriteValueToDB($Value, $DbHndl, $HashKey) \n"; if ((defined($DbHndl)) && ($DbHndl != 0)) { print "Value is $HashKey: $Value, To DB $DbHndl \n"; print $DbHndl "w|$HashKey|$Value\n"; } } sub ReadValue { (my $Key ,my $SocketHndl) = @_; print "ReadValue($Key ,$SocketHndl) \n"; if ((!defined($SocketHndl)) || ($SocketHndl == 0)) { print "SOCKET HANDLE IS EMTPRT \n"; return undef; } if (!DoesExists($Key ,$SocketHndl)) { print "CAN NOT FIND THE REC \n"; return undef; } $SocketHndl->send("r|$Key\n"); my $data=<$SocketHndl>; chomp($data); return $data; } sub DoesExists { (my $Key, my $SocketHndl) = @_; print "DoesExists($Key ,$SocketHndl) \n"; my $data; if ((defined($SocketHndl)) && ($SocketHndl != 0)) { $SocketHndl->send("e|$Key\n"); $data=<$SocketHndl>; chomp($data); } return $data; } #start the IPC server #----------------------------- MAIN ---------------------------- my $IsPortBusy = 0; my $socket; do { $IsPortBusy = 0; $ListenPort++; $socket = new IO::Socket::INET( LocalHost => '127.0.0.1', LocalPort => $ListenPort, Proto => 'tcp', Listen => $ListenPort, Blocking => 0, Reuse => 1) or $IsPortBusy = 1; } while ($IsPortBusy); $socket->close(); undef($socket); my $ServerListenPid = fork(); if (!$ServerListenPid) { $IsParent = 0; StartServer($ListenPort); } sleep 1; # Track spawned child processes. # This is a hash, keyed by the PID. # We'll use this later to mark them as finished. my %kids; for my $child_id (1..3) { my $pid = fork(); # PARENT: track kid if ($pid) { $kids{$pid} = 1; } # CHILD: dispatch to child-routine below. # Explicitly exit, in case the child code neglects. else { dispatch_child( $$ ); exit(0); } } print "Main code now waiting for all children.\n"; # Wait for all children to finish. # The signal handler, reap_kids(), catches finished children. # Just continue to sleep if there are pending processes. while( scalar(keys %kids) > 0 ) { sleep 1; } # That's all the main code does. print "All done with main code.\n"; exit(0); # --- # Suborutines # --- # Child reaper. # This will be called when the kernel tells us a process has # finished running. It's possible more than 1 has done so. # We run this in a loop to reap all children. sub reap_kids { local $!; # good practice. avoids changing errno. while (1) { my $kid = waitpid( -1, POSIX->WNOHANG ); last unless ($kid > 0); # No more to reap. delete $kids{$kid}; # untrack kid. } } # Child dispatch code. # Here is where you write what your child does. # Ideally it should exit, but we enforce this above anyway. sub dispatch_child { my ($id) = @_; # passed from caller. print "Hello from child number $id\n"; # Sleep for a random number of seconds. # Between 5 and 10. my $seconds = 5 + int(rand(6)); sleep $seconds; print "Goodbye from child number $id\n"; # Be nice and explicitly exit: exit(0); }