Hello Monks,

I have written a short script as a pretentiously named 'proof of concept' for a project I am working on.

The project's aims are to create a daemon that accepts data and commands through a tcp socket, processes/prioritizes them and drives the data and formatting to an LCD screen over an i2c connection. In addition the daemon will respond to signals such as HUP to cause a re-initialization of the lcd device and USR1 to load custom characters.

The test script shown here does not include any of the lcd communication or command processing as I have this working already and it is not relevant to the test script.

As I have never written a Perl script to create a daemon, or use sockets or that is event driven, I would appreciate comments on my approach and programming details

The test script, so far works as I want ... The program is daemonized, the pid is stored in a file and error output is directed to an error file. The script responds to HUP and USR1 signals and data sent from another machine on the network is received and processed by the io socket.

For the test, the outputs are sent to a log file.

The three events: i/o, HUP & USR1 are handled in anonymous subroutines, but the data received by the i/o socket is then passed to a main loop for further processing using a condition variable with ->send.

The ->recv is in the main loop, and according to the documentation for AnyEvent, this blocks the loop from running until a ->send occurs. Can I just keep the loop running so that I can do other things?.

I am not sure if the way I have structured this is appropriate and of course my 'y' solution to the 'x' problem may not be the best way to solve my issue.

The test script responds to the following series of external commands:

TestEvent.pl sudo kill -USR1 $(cat events.pid) SktClnt.pl Enter data to send: A.B.C sudo kill -HUP $(cat events.pid)

... with this in the events.log file

25-04-2020 18:03:46, Port: 55129 looping 0 25-04-2020 18:04:02, User 1 signal received 25-04-2020 18:04:11, Connection received from 192.168.0.153 Data: A.B.C loop data: A.B.C 25-04-2020 18:04:20, Hangup

Here is the script

#!/usr/bin/perl # EventsTest.pl # Version 1.0, 25 April 2020 use Sys::HostIP; use Daemon::Daemonize qw( :all ); use IO::Socket::INET; use Event; use AnyEvent; use Date::Calc qw( Today_and_Now ); use strict; use warnings; $|++; # ********************************************************** # # ************** Variables to be set by user *************** # # ********************************************************** # base path/name for log files (e.g. /home/anita2r/events.log) my $base = "/home/anita2R/events"; # port for socket connection my $port = 55129; # ********************************************************** # # ****************** Create log files etc. ***************** # # ********************************************************** # # Setup log, error and pid files my $error_log = "$base.err"; my $pid_file = "$base.pid"; my $msg_log = "$base.log"; # clear error and log files truncate $error_log, 0; truncate $msg_log, 0; # ********************************************************** # # ************* Create a communications socket ************* # # ********************************************************** # # create a socket and log port number my $hostip = Sys::HostIP->new; my $ip = $hostip->ip; # save port to log file my $DtTm = DtTmStmp(); open( my $fh, '>>', $msg_log ); print $fh "$DtTm, Port: $port\n"; close $fh; # setup socket my $skt = IO::Socket::INET->new( Listen => 1, LocalAddr => $ip, LocalPort => $port, Proto => 'tcp', Reuse => 1, ) or die "$! ... Can't open socket on port $port\n"; # ********************************************************** # # ******************** Signal handlers ********************* # # ********************************************************** # # ********************************************************** # # HUP signal handler # for this test HUP will log and close the script my $wtforhup = AnyEvent->signal( signal => "HUP", cb => sub { my $DtTm = DtTmStmp(); open( my $fh, '>>', $msg_log ); print $fh "$DtTm, Hangup\n"; close $fh; # clear the pid file and stop the daemon delete_pidfile( $pid_file ); exit 1; } ); # ********************************************************** # # USR1 signal handler # for this test USR1 will just add an entry to the log my $wtforusr1 = AnyEvent->signal( signal => "USR1", cb => sub{ my $DtTm = DtTmStmp(); open( my $fh, '>>', $msg_log ); print $fh "$DtTm, User 1 signal received\n"; close $fh; } ); # ********************************************************** # # IO socket handler # read data, log receive # and pass it on for additional processing my $data; my $iocv = AnyEvent->condvar; my $wtforio = AnyEvent->io( fh => \*$skt, poll => 'r', cb => sub{ my $lskt = $skt->accept(); while( <$lskt> ) { $data = $_; chomp $data; my $hostip = $lskt->peerhost(); # log received data my $DtTm = DtTmStmp(); open( my $fh, '>>', $msg_log ); print $fh "$DtTm, Connection received from $hostip\n"; print $fh "Data: $data\n"; close $fh; } close( $lskt ); # send data for further processing # $iocv->recv is in main loop $iocv->send( $data ); } ); # ********************************************************** # # *********************** Daemonize ************************ # # ********************************************************** # # daemonize, redirect errors & save new pid daemonize( close => 'std', stderr => $error_log, ); write_pidfile( $pid_file ); # ********************************************************** # # ********************* Initialization ********************* # # ********************************************************** # # In the real program, various initialization routines # are carried out before entering the main program loop # ********************************************************** # # ******************* Main Program Loop ******************** # # ********************************************************** # my $loop = 1; my $a = 0; while( $loop ) { # just to show whether the loop is running # one entry every 5 seconds if( $a % 5 == 0) { open( $fh, '>>', $msg_log ); print $fh "looping $a\n"; close $fh; } $a++; sleep 1; # $iocv-recv blocks until an $iorecv->send my $data = $iocv->recv; open( $fh, '>>', $msg_log ); print $fh "loop data: $data\n"; close $fh; # done with this cv undef $iocv; # setup a fresh cv - loop will be blocked until next send $iocv = AnyEvent->condvar; } exit 0; # ********************************************************** # # ****************** General subroutines ******************* # # ********************************************************** # # ********************************************************** # # date/time stamp sub DtTmStmp { my( $yr, $mo, $dy, $hr, $mi, $se ) = Today_and_Now(); my $DtTm = sprintf( "%02d-%02d-%04d %02d:%02d:%02d", $dy, $mo, $yr, $hr, $mi, $se ); return $DtTm; } # ********************************************************** #

Regards

anita2R


In reply to AnyEvents - mainly by anita2R

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.