⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch14.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 3 页
字号:
fixed length records you would use:<BR>

32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# read

PIPE_R,$buf,20;<BR>

33&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print

&quot;Child: Received $buf \n&quot;;<BR>

34&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

35&nbsp;&nbsp;&nbsp;&nbsp; }</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

Line 2 of this listing sets the output buffers to be flushed as

soon as they are written to. Line 6 creates the pipe for you to

make <TT><FONT FACE="Courier">PIPE_R</FONT></TT> and <TT><FONT FACE="Courier">PIPE_W</FONT></TT>

valid handles. We immediately do a fork in line 10.

<P>

After the fork, there are actually four handles: two <TT><FONT FACE="Courier">PIPE_R</FONT></TT>

handles and two <TT><FONT FACE="Courier">PIPE_W</FONT></TT> handles.

Because the parent does not want to read its own echo on <TT><FONT FACE="Courier">PIPE_R</FONT></TT>,

it closes <TT><FONT FACE="Courier">PIPE_R</FONT></TT>. Similarly,

the child has no reason to write to itself, so it closes <TT><FONT FACE="Courier">PIPE_W</FONT></TT>.

Then the parent writes to the <TT><FONT FACE="Courier">PIPE_W</FONT></TT>

handle while the child reads from the <TT><FONT FACE="Courier">PIPE_R</FONT></TT>

handle.

<P>

The following lines are the output from this program. Note how

the output from the child and parent process is intermixed. This

is because both processes are running at the same priority and

accessing the output device (<TT><FONT FACE="Courier">stdout</FONT></TT>)

at the same time.

<BLOCKQUOTE>

<TT><FONT FACE="Courier">hmm.. okParent:<BR>

&nbsp;Child:Child: Received [Sending: 0]<BR>

<BR>

Child: Received [Sending: 1]<BR>

<BR>

Child: Received [Sending: 2]<BR>

<BR>

Child: Received [Sending: 3]<BR>

<BR>

Child: Received [Sending: 4]</FONT></TT>

</BLOCKQUOTE>

<P>

Pipes are great when used between related processes. However,

if you want to communicate between two different processes, you

have to use FIFOs. A <I>FIFO</I> is also referred to as a <I>named

pipe</I>. Unrelated processes use named pipes to talk to each

other. The FIFO appears like a normal filename.

<P>

In Listing 14.4, line 6 names the FIFO pathname as it would appear

in the output from an <TT><FONT FACE="Courier">ls</FONT></TT>

command. In line 7, the FIFO is created with a system call to

the command <TT><FONT FACE="Courier">mkfifo</FONT></TT> using

the <TT><FONT FACE="Courier">-m</FONT></TT> option and pathname

used in line 6. The <TT><FONT FACE="Courier">unless</FONT></TT>

clause checks to see whether such a FIFO already exists before

attempting to recreate it. The code in line 8 actually opens the

FIFO after it is created. Then, in lines 9 through 11, you create

a string with the current date and send it to the FIFO. In line

12, you close the FIFO. The FIFO is not destroyed when it is closed

at line 12. You have to unlink the pathname-that is, remove the

FIFO by name to get rid of it, which is shown in line 14.

<P>

You can use an <TT><FONT FACE="Courier">ls</FONT></TT> command

on the FIFO name to see whether it exists. A way to test whether

a filename is a FIFO is to use the option <TT><FONT FACE="Courier">-p</FONT></TT>

on the filename from within a Perl script.

<HR>

<BLOCKQUOTE>

<B>Listing 14.4. Using FIFOs.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 #<BR>

&nbsp;3 # Create a fifo and

then return the date<BR>

&nbsp;4 # back to the caller when FIFO is read.<BR>

&nbsp;5 #<BR>

&nbsp;6 $path = &quot;./ch14_fifo&quot;;<BR>

&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;

unless (-p $path) { system(&quot;mkfifo -m 0666 $path&quot;);

}<BR>

&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp; open(FIFO,&quot;&gt; $path&quot;)

|| die &quot;Cannot open $! \n&quot;;<BR>

&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;

$date = `date`;<BR>

10&nbsp;&nbsp;&nbsp;&nbsp; chop($date);<BR>

11&nbsp;&nbsp;&nbsp;&nbsp; print FIFO &quot;[$date]&quot;;<BR>

12&nbsp;&nbsp;&nbsp;&nbsp; close FIFO;<BR>

13 # Remove when done.<BR>

14 unlink $path;</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

The FIFO is opened in line 8. Now the program blocks until there's

something on the other end trying to read from it. Using a command

like <TT><FONT FACE="Courier">cat ch14_fifo</FONT></TT> triggers

line 9. The program then gets the system date and prints it out

to the FIFO. Line 14 cleans up after itself.

<P>

You would probably want to have a signal handler to clean up if

a terminating signal arrives before input is read from the FIFO

and the program exits before destroying the FIFO. This is the

reason for the <TT><FONT FACE="Courier">unless</FONT></TT> clause,

which checks for any existing FIFOs before creating a new one.

The signal to catch is <TT><FONT FACE="Courier">SIGPIPE</FONT></TT>

for broken pipes. To trap <TT><FONT FACE="Courier">SIGPIPE</FONT></TT>,

you have to add this segment to your code:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">sub pipeHandler {<BR>

&nbsp;&nbsp;&nbsp;&nbsp;my $sig = shift @_;<BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">print

&quot; Caught SIGPIPE: $sig $1 \n&quot;;<BR>

&nbsp;&nbsp;&nbsp;&nbsp;exit(1);<BR>

}<BR>

<BR>

$SIG{PIPE} = \&amp;pipeHandler;</FONT></TT>

</BLOCKQUOTE>

<H2><A NAME="UsingopenforIpc"><FONT SIZE=5 COLOR=#FF0000>Using

</FONT><TT><FONT SIZE=5 COLOR=#FF0000 FACE="Courier">open()</FONT></TT><FONT SIZE=5 COLOR=#FF0000>

for Ipc</FONT></A></H2>

<P>

The <TT><FONT FACE="Courier">open()</FONT></TT> statement can

be used to start communication pipes. The catch is that these

pipes are unidirectional. To read the results from a process,

put <TT><FONT FACE="Courier">|</FONT></TT> at the end of the command

being executed. To write your results to the standard input of

a process, put <TT><FONT FACE="Courier">|</FONT></TT> at the start

of the command.

<P>

For example, here's how to write your results to the sendmail

mailing program:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">open(LOG, &quot;| /usr/apps/formatData

 | /usr/bin/sendmail &quot;);</FONT></TT>

</BLOCKQUOTE>

<P>

To read the results back from a process, use a line like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">open(READINGS, &quot;/usr/apps/commProgram

|&quot;);</FONT></TT>

</BLOCKQUOTE>

<P>

As an example, consider the program in Listing 14.5, which prints

the names of the files with the string passed to them at the command-line

argument. It then lists all the files within the associative array

<TT><FONT FACE="Courier">fname</FONT></TT>.

<HR>

<BLOCKQUOTE>

<B>Listing 14.5. Storing results of a command in an array.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Storing results from

a program in an array.<BR>

&nbsp;3 my %fname = ();<BR>

&nbsp;4 #&nbsp;&nbsp;Open all files with names ending in .pl<BR>

&nbsp;5 open(IncOMING,&quot;grep

ARGV[1] *.pl |&quot;);<BR>

&nbsp;6 while (&lt;IncOMING&gt;) {<BR>

&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;

($name,@line) =&nbsp;&nbsp;split(':',$_);<BR>

&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp; if (!$fname{$name}) {<BR>

&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fname{$name}

= $name;<BR>

10&nbsp;&nbsp;&nbsp;&nbsp; }<BR>

11 }<BR>

12 close IncOMING;<BR>

13<BR>

14 while (($key,$value) = each (%fname)) {<BR>

15&nbsp;&nbsp;&nbsp;&nbsp; print &quot;File: &quot; . $key . &quot;\n&quot;;

<BR>

16 }</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

It's probably tempting to use the back ticks to run a program

for you and collect the results. For example, <TT><FONT FACE="Courier">$a

= `who`</FONT></TT> returns the entire results of the <TT><FONT FACE="Courier">who</FONT></TT>

command in variable <TT><FONT FACE="Courier">$a</FONT></TT>. It's

impractical to use this method to collect results from a verbose

command. Using a command like <TT><FONT FACE="Courier">$a=`ls

-lr`</FONT></TT> is a lot slower than actually opening a file

handle to the output of this command and then processing it one

line at a time. The problem is that the entire result of the command

is stored in variable <TT><FONT FACE="Courier">$a</FONT></TT>,

chewing up memory and time while <TT><FONT FACE="Courier">$a</FONT></TT>

is appended to. It's easier and far more efficient to simply read

from the output in manageable chunks.

<P>

Use two pipes to do bidirectional communications. Do not use a

statement with a <TT><FONT FACE="Courier">|</FONT></TT> at end

of the command. Perl does not allow commands using this syntax:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">open(HANDLE, &quot;| sort |&quot;);</FONT></TT>

</BLOCKQUOTE>

<P>

Perl gives an error message about not being able to perform bidirectional

pipes.

<P>

The <TT><FONT FACE="Courier">open()</FONT></TT> function can accept

a file argument of either <TT><FONT FACE="Courier">-|</FONT></TT>

or <TT><FONT FACE="Courier">|-</FONT></TT>. Accepting either of

these parameters forks a child connected to the file handle you've

just opened. The child is then running the same program as the

parent. The return value from the call to <TT><FONT FACE="Courier">open()</FONT></TT>

is the process ID of the child or zero for the parent. The function

dies if it cannot fork within the <TT><FONT FACE="Courier">open()</FONT></TT>

call. Here's a sample usage of <TT><FONT FACE="Courier">-|</FONT></TT>

to create a receiving child:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$| = 1;&nbsp;&nbsp;&nbsp;# Always do

unbuffered IO here.<BR>

<BR>

$pid = open(MYHANDLE, &quot;|-&quot;);<BR>

if ($pid == 0) {<BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">#parent

acts as server<BR>

&nbsp;&nbsp;&nbsp;&nbsp;print MYHANDLE, &quot; something&quot;;

<BR>

} else {<BR>

&nbsp;&nbsp;&nbsp;&nbsp;#child acts as receiver.<BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">getSomething

= &lt;MYHANDLE&gt;;<BR>

}</FONT></TT>

</BLOCKQUOTE>

<P>

An implicit <TT><FONT FACE="Courier">fork()</FONT></TT> is possible

with the <TT><FONT FACE="Courier">open2()</FONT></TT> command.

Basically, with this call you start off two processes running

the same code. The child process ID is returned to the client.

Errors cause the function to bail out. The <TT><FONT FACE="Courier">Ipc::Open2</FONT></TT>

module is required for this to work. Also, you have to make sure

you are reading and writing continuously to this buffer. Be careful

to run only programs for which you know the input and output sequences.

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$|&nbsp;&nbsp;= 1;<BR>

$pid = open('BI_R', 'BI_W', &quot;myPerlScript&quot;);<BR>

if ($pid == 0) {<BR>

&nbsp;&nbsp;&nbsp;&nbsp;#parent acts as server<BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">print

B_R, &quot; something&quot;;<BR>

} else {<BR>

</FONT></TT>&nbsp;&nbsp;&nbsp;&nbsp;<TT><FONT FACE="Courier">#child

acts as receiver.<BR>

&nbsp;&nbsp;&nbsp;&nbsp;getSomething = &lt;MYHANDLE&gt;;<BR>

}</FONT></TT>

</BLOCKQUOTE>

<P>

There is an <TT><FONT FACE="Courier">open3()</FONT></TT> function

call, too, that adds <TT><FONT FACE="Courier">STDERR</FONT></TT>

to the list of opened files with which you may work.

<H2><A NAME="Summary"><FONT SIZE=5 COLOR=#FF0000>Summary</FONT></A>

</H2>

<P>

This is a very quick introduction to using UNIX pipes and signals

with Perl. Signals are a way of asynchronously telling a process

about an event. Generally, signals can only be caught and an error

message displayed about the type of signal through the use of

a subroutine, called a <I>handler</I>. The types of signals vary

depending on the type of UNIX system you use.

<P>

Using pipes is a method of communication between two processes

that is old, yet still heavily used in UNIX. If a pipe (<TT><FONT FACE="Courier">|</FONT></TT>)

is placed at the beginning of a filename in an <TT><FONT FACE="Courier">open()</FONT></TT>

call, you'll be writing to a pipe with a UNIX command, file, or

device at the other end. If <TT><FONT FACE="Courier">command |</FONT></TT>

is placed at the end of a filename to the <TT><FONT FACE="Courier">open()</FONT></TT>

call, you'll be reading the output of the command. Bi-directional

and even tridirectional pipes are possible using the <TT><FONT FACE="Courier">open2()</FONT></TT>

and <TT><FONT FACE="Courier">open3()</FONT></TT> calls.

<P>

<HR WIDTH="100%"></P>



<CENTER><P><A HREF="ch13.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch13.htm"><IMG SRC="pc.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/pc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="#CONTENTS"><IMG SRC="cc.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/cc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="index.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/index.htm"><IMG SRC="hb.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/hb.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="ch15.htm" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/ch15.htm"><IMG 

SRC="nc.gif" tppabs="http://www.mcp.com/815097600/0-672/0-672-30891-6/nc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A></P></CENTER>



<P>

<HR WIDTH="100%"></P>



</BODY>

</HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -