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

I need to:
Create a named pipe with a unique named.
Write a command to a (different) known named pipe.
Listen for the response on my unique named pipe.
Destroy the unique named pipe.

I have no problems creating and destroying the named pipe, however I've never done anything with named pipes before and though I've read up on their usage I'm not sure I'm reading/writing to them in a "safe" manner. In particular, I'm aware that if there is no corresponding writer/reader of the pipe then the write/read operation will block indefinitely. So when reading/writing to the pipe, i need to have a timeout. I thought the best way to do this would be to spawn a child process and make the parent kill the child if it took to long.
The "Reading" code.
my $result; my $named_pipe_name = '/path/to/pipe'; my $timeout = 5; #check to see if named pipe exists if (-p $named_pipe_name) { #fork in such a manner as to enable us to get out what the child # reads from the NP if (my $childpid = open(FROMCHILD, "-|")) { #parent #set up the a SIGCHLD handler that will read what the child has # written local $SIG{CHLD} = sub { $result .= <FROMCHILD>; }; #wait for our timeout sleep ($timeout); #kill the child (if it still exists) kill 'HUP', $childpid; } else { #child #Open for reading only. note using sysopen without create flag # to prevent creation of the named pipe as a normal file if (sysopen(FIFO, $named_pipe_name, O_RDONLY)) { my $return_string; #read from the name pipe till EOF while(my $this_line = <FIFO>) { chomp($this_line); $return_string .= $this_line; } close(FIFO); #tell the parent what we read print STDOUT $return_string; } else { print STDOUT "ERROR: Reading $named_pipe_name: $!"; } #exit causes the SIGCHLD to be sent. exit; } } print STDOUT $result;
The above works but I not confident it is the best way of doing this or even that it will be robust in the real world. Any enlightenment much appreciated!

Replies are listed 'Best First'.
Re: Reading from a Named Pipe
by ikegami (Pope) on Sep 28, 2006 at 03:21 UTC
    alarm will interrupt a read.
      ah ha! So something like:
      if (-p $named_pipe_name) { eval { local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required alarm $timeout; if (sysopen(FIFO, $named_pipe_name, O_RDONLY)) { while(my $this_line = <FIFO>) { chomp($this_line); $result .= $this_line; } close(FIFO); } else { $errormsg = "ERROR: Failed to open named pipe $named_pipe_name + for reading: $!"; } alarm 0; }; if ($@) { if ($@ eq "alarm\n") { # timed out $errormsg = "Timed out reading from named pipe $named_pipe_nam +e"; } else { $errormsg = "Error reading from named pipe: $!"; } } else { # didn't time out print STDOUT "$result\n"; } }
Re: Reading from a Named Pipe
by cdarke (Prior) on Sep 28, 2006 at 07:43 UTC
    One of the points about a named pipe is that you can use them just like an ordinary file. There are exceptions, like you can't mmap them or do a seek, but generally they are transparent.
    I see that you are opening an anonymous pipe with my $childpid = open(FROMCHILD, "-|")). Forgive me if I have misunderstood your code, but I wonder if you are confusing anonymous pipes (indicated by the | symbol) and named pipes? Generally anonymous pipes are used for communication between related processes (parent-child, for example), and named pipes (on UNIX, also called FIFO's) for communication between unrelated processes.
      I wonder if you are confusing anonymous pipes (indicated by the | symbol) and named pipes?

      I started to think the very same thing after I posted my reply. It seems likely that's what the OP meant. Another point to keep in mind, you can create anonymous pipes using the pipe function, too. You don't have to use Perl's forking-pipe open call (though, I admit, it is very convenient).

      The reason I've done the "open" with the anonymous pipe is to enable the parent to get output from the child.
      The crux here is that the read from the named pipe my $this_line = <FIFO> could potential block indefinitely. That is why it is nessary (AFAIK) to fork (create the child) and have a timeout which kills the child if it does not manage to read from the pipe.
Re: Reading from a Named Pipe
by revdiablo (Prior) on Sep 28, 2006 at 04:20 UTC
    Create a named pipe with a unique named.

    I might be missing something, but I don't see any code here that creates a "unique named" pipe. Nonetheless, that seems like a somewhat strange requirement. The point of a named pipe is that you know its name ahead of time, and you can use it from separate processes. If you only want a temporary pipe to communicate between two processes, a named pipe doesn't seem like the right thing. Again, from your code, it doesn't really look like that's what you're doing, but your text description seemed a bit strange.

      I have no problems creating or destroying the pipe as required, the area i'm concerned about is reading/writing from NP's. Hence I've only shown the code that is to READ from the named pipe.