rimvydazas has asked for the wisdom of the Perl Monks concerning the following question:

I was trying to find some info about Proc::Daemon thingy, but there is no much about it. I want one of my Perl scripts to run as a daemon since I need to capture and parse telephone calls data coming on the socket. As far as I understand, Proc::Daemon detaches STDOUT, and STDERR from the terminal. What about STDIN? What I mean is if I use Proc::Daemon, will STDIN still be listening on the socket? I am new at Perl, and all advices will be appreciated. Also, should I use separate files for the main code and startup script (the one with Proc::Daemon)? Thank you.

Replies are listed 'Best First'.
Re: daemon with Perl on Linux
by Joost (Canon) on Nov 28, 2007 at 21:16 UTC
    Looking at the source of Proc::Deamon, it actually binds STDIN STDOUT and STDERR to /dev/null, so none of them will be bound to your terminal. It also uses fork() and POSIX::setsid() which should ensure that the process is completely disconnected from the terminal in all other ways. (update: note that this is more or less exactly what a daemon IS. if you don't want this behaviour, you probably don't want to run your code as a daemon at all)

    Daemons usually don't read anything from STDIN anyway (since they're supposed to be run completely in the background). Is there a reason you want to use STDIN to read from a socket instead of opening the socket in the daemon process?

    It may make sense to put the "main code" in a separate module (see perlmod) for two reasons: one, so you can logically separate the daemon setup code from the processing code (i.e. just to make it easy to find the code you want and ignore the code you're not currently interested in); and two, if you put the processing code in a module you can use that same processing code in a program that doesn't act as a daemon (for instance, when testing the processing code, you can call it from a simple test script that gives output to STDOUT).

      OK, now I am confused. When script is listening for the data on the socket, isn't STDIN whatever script receives from that socket? If so, then whenever I make the script to run as a daemon, I won't be able to receive anything on the socket since STDIN will be detached. Am I right? What I have is a script listening for the data on the socket, and I want that script to run in the background all the time and process whatever I get from that socket. By the way, how should I enable this daemon to run at startup? Is it enough just to add it to one of startup files, or should I use runlevel folders?... Thanks for the help.
        STDIN is the name for one of the 3 standard file handles that a process inherits from its parent process. If you start a program from the command line without input redirection, STDIN is bound to the terminal, so that anything that's typed in at the terminal is delivered to the program via its STDIN handle.

        But you can also start programs with STDIN bound to something else:

        $ my-program < a-file # or $ some-program | some-other-program
        etc.

        In general when you open a socket you get/use a new filehandle especially for that socket, since even though it's possible to re-open STDIN in some other way later (through a socket or file or whatever) that would IMO just be confusing.

        Though most unix systems have a fairly similar ways to deal with startup/shutdown scripts through various runlevel files etc, the differences in how to administrate those files easily are different enough that you should probably just look up your system's documentation.

        If you want to become better informed about all these issues, I recommend Advanced Programming in the UNIX Environment (2nd edition).

Re: daemon with Perl on Linux
by Akoya (Scribe) on Nov 28, 2007 at 20:45 UTC
    I recently had to write a daemon. Due to corporate policies, I was unable to use non-core modules. The shell of the daemon is actually not very complex though...
    use POSIX qw{ setsid getcwd close sysconf _SC_OPEN_MAX }; ... foreach my $i (0 .. openmax()) { POSIX::close($i); } open(STDIN, "+>/dev/null"); open(STDOUT, "+>&STDIN"); open(STDERR, "+>&STDIN"); # ignore these signals for (qw(TSTP TTIN TTOU PIPE POLL STOP CONT CHLD)) { $SIG{$_} = 'IGNORE' if (exists $SIG{$_}); } # handle these signals for (qw(INT HUP ABRT QUIT TRAP TERM)) { $SIG{$_} = 'interrupt' if (exists $SIG{$_}); } unless (my $pid = fork()) { exit if $pid; POSIX::setsid; # set session id chdir '/'; # change to root directory umask 0; # clear the file creation mask while(1) { # do whatever your daemon needs to do ... } } sub interrupt { # do whatever to gracefully shutdown ... die "$0 terminated successfully.\n"; }
    Hope this is useful to you. As always, any suggestions are welcome. --Akoya
      I found a couple of scripts similar to this one. As far as I understand, this script will do check ups on "whatever daemon needs to" check on. But what if my daemon needs to listen to the socket, but not to do any kind of check ups? Can I somehow to implement that? It might sound dumb to you, but I am newbie... :]
Re: daemon with Perl on Linux
by jettero (Monsignor) on Nov 28, 2007 at 19:48 UTC

    I'm not familiar with that particular module. If you want to get a really simple service up quickly, I'd look at Net::Daemon. If you scroll down to the example, you can just cut and paste that and edit to suit your needs.

    -Paul

Re: daemon with Perl on Linux
by tuxz0r (Pilgrim) on Nov 28, 2007 at 20:59 UTC
    Something else to look at might be POE, which makes it really easy to write daemon processes, servers and more under an event driven style of coding. We've been looking it over here at my work and it sure beats coding up background servers by hand.

    ---
    echo S 1 [ Y V U | perl -ane 'print reverse map { $_ = chr(ord($_)-1) } @F;'
    Warning: Any code posted by tuxz0r is untested, unless otherwise stated, and is used at your own risk.

Re: daemon with Perl on Linux
by rimvydazas (Novice) on Nov 30, 2007 at 20:01 UTC
    Ok, I added the following subroutine to my main script. Maybe it sounds funny, but where exactly in the main script I should run this subroutine? My script starts with "use" thingies, then global variables, command arguments (%ARGV), and the rest subroutines and socket connections.
    sub daemonize { # Change current working directory to root chdir("$logroot") or die "Cannot change to $logroot: $!"; # Set umask to 0 umask(0); # Detach STD file handles from the terminal open (STDIN,"/dev/null") or die "Cannot read to /dev/null: +$!"; open (STDOUT,">>$stoutp") or die "Cannot write to $stoutp: +$!"; open (STDERR,">>$sterr") or die "Cannot write to $sterr: $! +"; # PID forking defined(my $pid = fork) or die "Cannot fork: $!"; exit if $pid; setsid or die "Cannot set session ID: $!"; }
    By the way, is there any way to assign specific PID for the process? The thing is that I need to start three processes from the same script to listen on three different ports. I need to check if these processes are running using cron.