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

📄 ch16_12.htm

📁 By Tom Christiansen and Nathan Torkington ISBN 1-56592-243-3 First Edition, published August 1998
💻 HTM
字号:
<HTML><HEAD><TITLE>Recipe 16.11. Making a Process Look Like a File with Named Pipes (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen &amp; Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly &amp; Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:44:00Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch16_01.htm"TITLE="16. Process Management and Communication"><LINKREL="prev"HREF="ch16_11.htm"TITLE="16.10. Communicating Between Related Processes"><LINKREL="next"HREF="ch16_13.htm"TITLE="16.12. Sharing Variables in Different Processes"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch16_11.htm"TITLE="16.10. Communicating Between Related Processes"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 16.10. Communicating Between Related Processes"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch16_01.htm"TITLE="16. Process Management and Communication"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch16_13.htm"TITLE="16.12. Sharing Variables in Different Processes"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 16.12. Sharing Variables in Different Processes"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch16-20777">16.11. Making a Process Look Like a File with Named Pipes</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch16-pgfId-1960">Problem</A></H3><PCLASS="para"><ACLASS="indexterm"NAME="ch16-idx-1000006359-0"></A><ACLASS="indexterm"NAME="ch16-idx-1000006359-1"></A><ACLASS="indexterm"NAME="ch16-idx-1000006359-2"></A>You want a process to intercept all access to a file. For instance, you want to make your <EMCLASS="emphasis">~/.plan</EM> file a program that returns a random quote.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch16-pgfId-1966">Solution</A></H3><PCLASS="para">Use named pipes. First create one, probably from your shell:</P><PRECLASS="programlisting">% mkfifo /path/to/named.pipe</PRE><PCLASS="para">Here's a reader for it:</P><PRECLASS="programlisting">open(FIFO, &quot;&lt; /path/to/named.pipe&quot;)         or die $!;while (&lt;FIFO&gt;) {    print &quot;Got: $_&quot;;}close(FIFO);</PRE><PCLASS="para">Here's a writer for it:</P><PRECLASS="programlisting">open(FIFO, &quot;&gt; /path/to/named.pipe&quot;)         or die $!;print FIFO &quot;Smoke this.\n&quot;;close(FIFO);</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch16-pgfId-1994">Discussion</A></H3><PCLASS="para">A named pipe, or FIFO as they are also known, is a special file that acts as a buffer to connect processes on the same machine. Ordinary pipes also allow processes to communicate, but those processes must have inherited the filehandles from their parents. To use a named pipe, a process need know only the named pipe's filename. In most cases, processes don't even need to be aware that they're reading from a FIFO.</P><PCLASS="para">Named pipes can be read from and written to just as though they were ordinary files (unlike Unix-domain sockets as discussed in <ACLASS="xref"HREF="ch17_01.htm"TITLE="Sockets">Chapter 17, <CITECLASS="chapter">Sockets</CITE></A>). Data written into the FIFO is buffered up by the operating system, then read back in the order it was written in. Because a FIFO acts as a buffer to connect processes, opening one for reading will block until another process opens it for writing, and vice versa. If you <CODECLASS="literal">open</CODE> for read and write using the +&lt; mode to <CODECLASS="literal">open</CODE>, you won't block (on most systems) because your process could be both reader and writer.</P><PCLASS="para">Let's examine how to use a named pipe so people will get a different file each time they <EMCLASS="emphasis">finger</EM> you. To create a named pipe, use <EMCLASS="emphasis">mkfifo</EM> or <EMCLASS="emphasis">mknod</EM> to create a named pipe called <EMCLASS="emphasis">.plan</EM> in your home directory:</P><PRECLASS="programlisting">% mkfifo ~/.plan                    # isn't this everywhere yet?% mknod  ~/.plan p                  # in case you don't have mkfifo</PRE><PCLASS="para">On some systems, you must use <ICLASS="filename">mknod </I>(8). The location and names of these programs aren't uniform or necessarily obvious, so consult your system documentation to find out where these programs are.</P><PCLASS="para">The next step is to create a program to feed data to the programs that read from your ~<EMCLASS="emphasis">/.plan</EM> file. We'll just print the date and time, as shown in <ACLASS="xref"HREF="ch16_12.htm#ch16-15443"TITLE="dateplan">Example 16.9</A>.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch16-15443">Example 16.9: dateplan</A></H4><PRECLASS="programlisting">#!/usr/bin/perl -w# dateplan - place current date and time in .plan filewhile (1) {    open(FIFO, &quot;&gt; $ENV{HOME}/.plan&quot;)        or die &quot;Couldn't open $ENV{HOME}/.plan for writing: $!\n&quot;;    print FIFO &quot;The current time is &quot;, scalar(localtime), &quot;\n&quot;;    close FIFO;    sleep 1;}</PRE></DIV><PCLASS="para">Unfortunately, this won't always work, because some <EMCLASS="emphasis">finger</EM> programs and their attendant daemons check the size of the <EMCLASS="emphasis">.plan</EM> file before trying to read it. Because named pipes appear as special files of zero size on the filesystem, such clients and servers will not try to open or read from our named pipe, and the trick will fail.</P><PCLASS="para">In our <EMCLASS="emphasis">.plan</EM> example, the writer was a daemon. It's not uncommon for readers to be daemons as well. Take, for instance, the use of a named pipe to centralize logging from many processes. The log server reads log messages from the named pipe and can send them to a database or file. Clients write their messages to the named pipe. This removes the distribution logic from the clients, making changes to message distribution easy to implement.</P><PCLASS="para"><ACLASS="xref"HREF="ch16_12.htm#ch16-41177"TITLE="fifolog">Example 16.10</A> is a simple program to read two-line messages where the first line is the name of the service and the second line is the message being logged. All messages from <CODECLASS="literal">httpd</CODE> are ignored, while all messages from <CODECLASS="literal">login</CODE> are saved to <ICLASS="filename">/var/log/login</I>.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch16-41177">Example 16.10: fifolog</A></H4><PRECLASS="programlisting">#!/usr/bin/perl -w# <ACLASS="indexterm"NAME="ch16-idx-1000006360-0"></A>fifolog - read and record log msgs from fifouse IO::File;$SIG{ALRM} = sub { close(FIFO) };   # move on to the next queued processwhile (1) {    alarm(0);                       # turn off alarm for blocking open    open(FIFO, &quot;&lt; /tmp/log&quot;)        or die &quot;Can't open /tmp/log : $!\n&quot;;    alarm(1);                       # you have 1 second to log    $service = &lt;FIFO&gt;;    next unless defined $service;   # interrupted or nothing logged    chomp $service;    $message = &lt;FIFO&gt;;    next unless defined $message;   # interrupted or nothing logged    chomp $message;    alarm(0);                       # turn off alarms for message processing    if ($service eq &quot;http&quot;) {        # ignoring    } elsif ($service eq &quot;login&quot;) {        # log to /var/log/login        if ( open(LOG, &quot;&gt;&gt; /tmp/login&quot;) ) {            print LOG scalar(localtime), &quot; $service $message\n&quot;;            close(LOG);        } else {            warn &quot;Couldn't log $service $message to /var/log/login : $!\n&quot;;        }    }}</PRE></DIV><PCLASS="para">This program is more complicated than the <EMCLASS="emphasis">.plan</EM> program for several reasons. First and foremost, we don't want our logging server to block would-be writers for long. It's easy to imagine a situation where an attacker or misbehaving writer opens the named pipe for writing, but doesn't send a complete message. To prevent this, we use <CODECLASS="literal">alarm</CODE> and <CODECLASS="literal">SIGALRM</CODE> to signal us if we get stuck reading.</P><PCLASS="para">Only two exceptional conditions can happen when using named pipes: a writer can have its reader disappear, or vice versa. If a process is reading from a named pipe and the writer closes its end, the reading process will get an end of file (<CODECLASS="literal">&lt;&gt;</CODE> returns <CODECLASS="literal">undef</CODE>). If the reader closes the connection, though, the writer will get a <CODECLASS="literal">SIGPIPE</CODE> when it next tries to write there. If you disregard broken pipe signals with <CODECLASS="literal">$SIG{PIPE}</CODE> <CODECLASS="literal">=</CODE> <CODECLASS="literal">'IGNORE'</CODE>, your <CODECLASS="literal">print</CODE> will return a false value and <CODECLASS="literal">$!</CODE> will be set to <CODECLASS="literal">EPIPE</CODE>:</P><PRECLASS="programlisting">use POSIX qw(:errno_h);$SIG{PIPE} = 'IGNORE';# ...$status = print FIFO &quot;Are you there?\n&quot;;if (!$status &amp;&amp; $! == EPIPE) {    warn &quot;My reader has forsaken me!\n&quot;;    next;}</PRE><PCLASS="para">You may be asking "If I have 100 processes all trying simultaneously to write to this server, how can I be sure that I'll get 100 separate entries and not a jumbled mishmash with characters or lines from different processes?" That's a good question. The POSIX standard says that writes of less than <CODECLASS="literal">PIPE_BUF</CODE> bytes in size will be delivered atomically, i.e. not jumbled. You can get the <CODECLASS="literal">PIPE_BUF</CODE> constant from <CODECLASS="literal">POSIX</CODE>:</P><PRECLASS="programlisting">use POSIX;print _POSIX_PIPE_BUF, &quot;\n&quot;;</PRE><PCLASS="para">Fortunately, the POSIX standard also requires <CODECLASS="literal">PIPE_BUF</CODE> to be <EMCLASS="emphasis">at least</EM> 512 bytes. This means that all we have to do is ensure that our clients don't try to log more than 512 bytes at a time.</P><PCLASS="para">What if you want to log more than 512 bytes at a time? Then you split each large message into several smaller (fewer than 512 bytes) messages, preface each with the unique client identifier (process ID, say) and have the server reassemble them. This is similar to the processing involved in TCP/IP message fragmentation and reassembly.</P><PCLASS="para">Because a single named pipe doesn't allow bidirectional access between writer and reader, authentication and similar ways of preventing forged messages are hard to do (if not impossible). Rather than struggle to force such things on top of a model that doesn't accommodate them, you are better off using the filesystem's access control to restrict access to the file through the owner and group permissions on the named pipe.<ACLASS="indexterm"NAME="ch16-idx-1000006362-0"></A><ACLASS="indexterm"NAME="ch16-idx-1000006362-1"></A><ACLASS="indexterm"NAME="ch16-idx-1000006362-2"></A></P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch16-pgfId-2138">See Also</A></H3><PCLASS="para"><ICLASS="filename">mkfifo (8)</I> or <ICLASS="filename">mknod (8)</I> (if you have them); <ACLASS="xref"HREF="ch17_07.htm"TITLE="Using UNIX Domain Sockets">Recipe 17.6</A></P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch16_11.htm"TITLE="16.10. Communicating Between Related Processes"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 16.10. Communicating Between Related Processes"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="book"HREF="index.htm"TITLE="Perl Cookbook"><IMGSRC="../gifs/txthome.gif"ALT="Perl Cookbook"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch16_13.htm"TITLE="16.12. Sharing Variables in Different Processes"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 16.12. Sharing Variables in Different Processes"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">16.10. Communicating Between Related Processes</TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="index"HREF="index/index.htm"TITLE="Book Index"><IMGSRC="../gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228">16.12. Sharing Variables in Different Processes</TD></TR></TABLE><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><FONTSIZE="-1"></DIV<!-- LIBRARY NAV BAR --> <img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p> <a href="copyrght.htm">Copyright &copy; 2002</a> O'Reilly &amp; Associates. All rights reserved.</font> </p> <map name="library-map"> <area shape="rect" coords="1,0,85,94" href="../index.htm"><area shape="rect" coords="86,1,178,103" href="../lwp/index.htm"><area shape="rect" coords="180,0,265,103" href="../lperl/index.htm"><area shape="rect" coords="267,0,353,105" href="../perlnut/index.htm"><area shape="rect" coords="354,1,446,115" href="../prog/index.htm"><area shape="rect" coords="448,0,526,132" href="../tk/index.htm"><area shape="rect" coords="528,1,615,119" href="../cookbook/index.htm"><area shape="rect" coords="617,0,690,135" href="../pxml/index.htm"></map> </BODY></HTML>

⌨️ 快捷键说明

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