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

📄 00000015.htm

📁 一份很好的linux入门资料
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<HTML><HEAD>  <TITLE>BBS水木清华站∶精华区</TITLE></HEAD><BODY><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER>发信人:&nbsp;SuperSB&nbsp;(孤鹰),&nbsp;信区:&nbsp;Linux&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>标&nbsp;&nbsp;题:&nbsp;[转载]unix环境高级编程-15&nbsp;<BR>发信站:&nbsp;BBS&nbsp;水木清华站&nbsp;(Wed&nbsp;Mar&nbsp;15&nbsp;14:31:19&nbsp;2000)&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>发信人:&nbsp;taosm&nbsp;(128+64--&gt;cool),&nbsp;信区:&nbsp;unix&nbsp;&nbsp;<BR>标&nbsp;&nbsp;题:&nbsp;unix环境高级编程--第15章&nbsp;高级进程间通信&nbsp;&nbsp;<BR>发信站:&nbsp;西十八BBS&nbsp;(Sat&nbsp;Mar&nbsp;11&nbsp;14:00:43&nbsp;2000),&nbsp;转信&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;<BR>第十五章&nbsp;&nbsp;高级进程间通信&nbsp;&nbsp;<BR>15.1&nbsp;引言&nbsp;&nbsp;<BR>上一章说明了各种UNIX系统提供的IPC经典方法,包括:管道、FIFO、消息队列、信&nbsp;&nbsp;<BR>号量和共享存储。本章介绍某些高级的IPC以及它们的应用方法,包括:流管道和命&nbsp;&nbsp;<BR>名流管道。使用这些机制,我们可以在进程间传送打开文件描述符。在分别为每一&nbsp;&nbsp;<BR>个客户进程提供一个通道的系统中,这些通信机制使客户进程能与精灵服务进程会&nbsp;&nbsp;<BR>合。4。2BSD和SVR3。2最早提供这些高级形式的IPC,但是至今尚未广泛使用,也缺&nbsp;&nbsp;<BR>少参政文献。本章中很多思想来自Pressotto和Ritchie[1990]的论文。&nbsp;&nbsp;<BR>15.2&nbsp;流管道&nbsp;&nbsp;<BR>流管道是一个双向(全双工)管道。单个流管道就能向父、子进程提供双向的数据流&nbsp;&nbsp;<BR>。图15。1显示了观察流管道的两种方式。它与图14.2的唯一区别是双向箭头连线&nbsp;&nbsp;<BR>,这是因为流管道是全双工的。&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;实例&nbsp;&nbsp;<BR>我们用一个流管道再次实现了程序14.9的协作进程实例。程序15.1是新的main函数&nbsp;&nbsp;<BR>。add2协作进程与程序14.8中的相同。程序15.1调用了创建一个流管道的新函数s&nbsp;&nbsp;<BR>_pipe。(在下面将说明该函数的SVR4和4.3+BSD版本。)&nbsp;&nbsp;<BR>图15.1&nbsp;&nbsp;观察流管道的两种方式&nbsp;&nbsp;<BR>#include&nbsp;&lt;signal.h&gt;&nbsp;&nbsp;<BR>#include&nbsp;&quot;ourhdr.h&quot;&nbsp;&nbsp;<BR>static&nbsp;void&nbsp;sig_pipe(int);&nbsp;&nbsp;/*&nbsp;our&nbsp;signal&nbsp;handler&nbsp;*/&nbsp;&nbsp;<BR>int&nbsp;&nbsp;<BR>main(void)&nbsp;&nbsp;<BR>{&nbsp;&nbsp;<BR>&nbsp;int&nbsp;&nbsp;n,&nbsp;fd[2];&nbsp;&nbsp;<BR>&nbsp;pid_t&nbsp;pid;&nbsp;&nbsp;<BR>&nbsp;char&nbsp;line[MAXLINE];&nbsp;&nbsp;<BR>&nbsp;if&nbsp;(signal(SIGPIPE,&nbsp;sig_pipe)&nbsp;==&nbsp;SIG_ERR)&nbsp;&nbsp;<BR>&nbsp;&nbsp;err_sys(&quot;signal&nbsp;error&quot;);&nbsp;&nbsp;<BR>&nbsp;if&nbsp;(s_pipe(fd)&nbsp;&lt;&nbsp;0)&nbsp;&nbsp;&nbsp;/*&nbsp;only&nbsp;need&nbsp;a&nbsp;single&nbsp;stream&nbsp;pipe&nbsp;*/&nbsp;&nbsp;<BR>&nbsp;&nbsp;err_sys(&quot;pipe&nbsp;error&quot;);&nbsp;&nbsp;<BR>&nbsp;if&nbsp;(&nbsp;(pid&nbsp;=&nbsp;fork())&nbsp;&lt;&nbsp;0)&nbsp;&nbsp;<BR>&nbsp;&nbsp;err_sys(&quot;fork&nbsp;error&quot;);&nbsp;&nbsp;<BR>&nbsp;else&nbsp;if&nbsp;(pid&nbsp;&gt;&nbsp;0)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;parent&nbsp;*/&nbsp;&nbsp;<BR>&nbsp;&nbsp;close(fd[1]);&nbsp;&nbsp;<BR>&nbsp;&nbsp;while&nbsp;(fgets(line,&nbsp;MAXLINE,&nbsp;stdin)&nbsp;!=&nbsp;NULL)&nbsp;{&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;n&nbsp;=&nbsp;strlen(line);&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(write(fd[0],&nbsp;line,&nbsp;n)&nbsp;!=&nbsp;n)&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;err_sys(&quot;write&nbsp;error&nbsp;to&nbsp;pipe&quot;);&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(&nbsp;(n&nbsp;=&nbsp;read(fd[0],&nbsp;line,&nbsp;MAXLINE))&nbsp;&lt;&nbsp;0)&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;err_sys(&quot;read&nbsp;error&nbsp;from&nbsp;pipe&quot;);&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(n&nbsp;==&nbsp;0)&nbsp;{&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;err_msg(&quot;child&nbsp;closed&nbsp;pipe&quot;);&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;line[n]&nbsp;=&nbsp;0;&nbsp;/*&nbsp;null&nbsp;terminate&nbsp;*/&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(fputs(line,&nbsp;stdout)&nbsp;==&nbsp;EOF)&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;err_sys(&quot;fputs&nbsp;error&quot;);&nbsp;&nbsp;<BR>&nbsp;&nbsp;}&nbsp;&nbsp;<BR>&nbsp;&nbsp;if&nbsp;(ferror(stdin))&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;err_sys(&quot;fgets&nbsp;error&nbsp;on&nbsp;stdin&quot;);&nbsp;&nbsp;<BR>&nbsp;&nbsp;exit(0);&nbsp;&nbsp;<BR>&nbsp;}&nbsp;else&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;child&nbsp;*/&nbsp;&nbsp;<BR>&nbsp;&nbsp;close(fd[0]);&nbsp;&nbsp;<BR>&nbsp;&nbsp;if&nbsp;(fd[1]&nbsp;!=&nbsp;STDIN_FILENO)&nbsp;{&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(dup2(fd[1],&nbsp;STDIN_FILENO)&nbsp;!=&nbsp;STDIN_FILENO)&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;err_sys(&quot;dup2&nbsp;error&nbsp;to&nbsp;stdin&quot;);&nbsp;&nbsp;<BR>&nbsp;&nbsp;}&nbsp;&nbsp;<BR>&nbsp;&nbsp;if&nbsp;(fd[1]&nbsp;!=&nbsp;STDOUT_FILENO)&nbsp;{&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(dup2(fd[1],&nbsp;STDOUT_FILENO)&nbsp;!=&nbsp;STDOUT_FILENO)&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;err_sys(&quot;dup2&nbsp;error&nbsp;to&nbsp;stdout&quot;);&nbsp;&nbsp;<BR>&nbsp;&nbsp;}&nbsp;&nbsp;<BR>&nbsp;&nbsp;if&nbsp;(execl(&quot;./add2&quot;,&nbsp;&quot;add2&quot;,&nbsp;NULL)&nbsp;&lt;&nbsp;0)&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;err_sys(&quot;execl&nbsp;error&quot;);&nbsp;&nbsp;<BR>&nbsp;}&nbsp;&nbsp;<BR>}&nbsp;&nbsp;<BR>static&nbsp;void&nbsp;&nbsp;<BR>sig_pipe(int&nbsp;signo)&nbsp;&nbsp;<BR>{&nbsp;&nbsp;<BR>&nbsp;printf(&quot;SIGPIPE&nbsp;caught\n&quot;);&nbsp;&nbsp;<BR>&nbsp;exit(1);&nbsp;&nbsp;<BR>}&nbsp;&nbsp;<BR>程序15.1&nbsp;&nbsp;&nbsp;用流管道驱动add2过滤进程的程序&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;父程序只使用fd[0],子程序只使用fd[1]&nbsp;。因为流管道的每一端都是全双工的&nbsp;&nbsp;<BR>,所以父进程读、写fd[0],而子程序将fd[1]复制到标准输入和标准输出。图15.2显&nbsp;&nbsp;<BR>示了由此构成的各描述符。&nbsp;&nbsp;<BR>图15.2&nbsp;&nbsp;为协作进程安排的各描述符&nbsp;&nbsp;<BR>s_pipe函数定义为与标准pipe函数类似。它的调用参数与pipe相同,但返回的描述&nbsp;&nbsp;<BR>符以读&nbsp;写方式打开。&nbsp;&nbsp;<BR>实例一SVR4下的s_pipe函数&nbsp;&nbsp;<BR>程序15.2是s_pipe函数的SVR4版本。它只是调用创建全双工管道的标准pipe函数&nbsp;&nbsp;<BR>#include&nbsp;&quot;ourhdr.h&quot;&nbsp;&nbsp;<BR>int&nbsp;&nbsp;<BR>s_pipe(int&nbsp;fd[2])&nbsp;/*&nbsp;two&nbsp;file&nbsp;descriptors&nbsp;returned&nbsp;in&nbsp;fd[0]&nbsp;&amp;&nbsp;fd[1]&nbsp;*/&nbsp;&nbsp;<BR>{&nbsp;&nbsp;<BR>&nbsp;return(&nbsp;pipe(fd)&nbsp;);&nbsp;&nbsp;<BR>}&nbsp;&nbsp;<BR>程序15.2&nbsp;&nbsp;s_pipe函数的SVR4版本&nbsp;&nbsp;<BR>在系统V的早期版本中也可以创建流管道,但要进行的处理较多。有关SVR3.2下创建&nbsp;&nbsp;<BR>流管道的详细情况,请参阅Stevens[1990]。&nbsp;&nbsp;<BR>图15.3显示SVR4之下管道的基本结构。它主要是两个相互连接的流首。&nbsp;&nbsp;<BR>图15.3&nbsp;&nbsp;在SVR4之下的管道&nbsp;&nbsp;<BR>因为管道是一种流设备,我们可将处理模块压入管道的任一端。在15.5.1节,我们将&nbsp;&nbsp;<BR>用此技术提供一个可以装配的命名管道。&nbsp;&nbsp;<BR>实例一4.3+BSD之下的s_pipe函数&nbsp;&nbsp;<BR>程序15.3是s_pipe函数的BSD版本。此函数在4.2BSD及以后的各版本中起作用。它&nbsp;&nbsp;<BR>创建一对互连的UNIX域流套接口。&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;自4.2BSD开始,常规的管道已用此方式实现。但是,当调用pipe时,第一个描述&nbsp;&nbsp;<BR>符的写端和第二个描述符的读端都被关闭。为获得全双工管道,必须直接调用sock&nbsp;&nbsp;<BR>etpair。&nbsp;&nbsp;<BR>#include&nbsp;&lt;sys/types.h&gt;&nbsp;&nbsp;<BR>#include&nbsp;&lt;sys/socket.h&gt;&nbsp;&nbsp;<BR>#include&nbsp;&quot;ourhdr.h&quot;&nbsp;&nbsp;<BR>int&nbsp;&nbsp;<BR>s_pipe(int&nbsp;fd[2])&nbsp;/*&nbsp;two&nbsp;file&nbsp;descriptors&nbsp;returned&nbsp;in&nbsp;fd[0]&nbsp;&amp;&nbsp;fd[1]&nbsp;*/&nbsp;&nbsp;<BR>{&nbsp;&nbsp;<BR>&nbsp;return(&nbsp;socketpair(AF_UNIX,&nbsp;SOCK_STREAM,&nbsp;0,&nbsp;fd)&nbsp;);&nbsp;&nbsp;<BR>}&nbsp;&nbsp;<BR>程序15.3&nbsp;&nbsp;s_pipe函数的BSD版本。&nbsp;&nbsp;<BR>15.3&nbsp;传送文件描述符&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;在进程间传送打开文件描述符的能力是非常有用的。用此可以对客户/服务器&nbsp;&nbsp;<BR>应用进行不同的设计。它允许一个进程(典型地是一个服务器)处理与打开一个文件&nbsp;&nbsp;<BR>有关的所有操作(涉及的细节可能是:将网络名翻译为网络地址、拨号调制解调器、&nbsp;&nbsp;<BR>协商文件锁等。)以及向调用进程返回一描述符,该描述符可被用于以后的所有I/O&nbsp;&nbsp;<BR>函数。打开文件或&nbsp;设备的所有细节对客户而言都是透明的。&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.2BSD支持传送打开描述符,但其实施中有些错误。4.3BSD排除了这些错&nbsp;&nbsp;<BR>误。3.2&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;及以上版本都支持传送打开描述符。&nbsp;&nbsp;<BR>下面进一步说明&quot;从一个进程向另一个进程传送一打开文件描述符&quot;的含义。回忆图&nbsp;&nbsp;<BR>3.3,其中显示了两个进程,它们打开了同一文件。虽然它们共享同一v_node,但每个&nbsp;&nbsp;<BR>进程都有它自己的文件表项。当从一个进程向另一个进程传送一打开文件描述符时&nbsp;&nbsp;<BR>,我们想要发送进程和接收进程共享同一文件表项。图15.4示出了所希望的安排。&nbsp;&nbsp;<BR>在技术上,发送进程实际上向接受进程传送一个指向一打开文件表项的指针。该指&nbsp;&nbsp;<BR>针被分配存放在接收进程的第一个可用描述符项中。(注意,不要得到错觉以为发送&nbsp;&nbsp;<BR>进程和接收进程中的描述符编号是相同的,通常它们是不同的。)这种情况与在for&nbsp;&nbsp;<BR>k之后,父、子进程完全共享一个打开文件表项相同(回忆图8.1)。&nbsp;&nbsp;<BR>当发送进程将描述符传送给接收进程后,通常它关闭该描述符。发送进程关闭该描&nbsp;&nbsp;<BR>述符并不造成关闭该文件或设备,其原因是该描述符对应的文件仍需为接收进程打&nbsp;&nbsp;<BR>开(即使接收进程尚未接收到该描述符)。&nbsp;&nbsp;<BR>图15.4&nbsp;&nbsp;从上一进程传送一个打开文件至下一进程&nbsp;&nbsp;<BR>下面我们定义本章使用的三个函数(在第十八章也使用)以发送和接收文件描述符。&nbsp;&nbsp;<BR>本节将会给出对于SVR4和4.3+BSD的这三个函数的不同实现。&nbsp;&nbsp;<BR>_______________________________________________________________________&nbsp;&nbsp;<BR>______&nbsp;&nbsp;<BR>#include&nbsp;&quot;ourhdr.&quot;&nbsp;&nbsp;<BR>int&nbsp;send_fd(int&nbsp;spipefd,&nbsp;int&nbsp;filedes);&nbsp;&nbsp;<BR>int&nbsp;send_err(int&nbsp;spipefd,int&nbsp;status,&nbsp;const&nbsp;char&nbsp;*errmsg);&nbsp;&nbsp;<BR>&nbsp;两个函数返回:若成功为0,出错为-1&nbsp;&nbsp;<BR>int&nbsp;recv_fd(int&nbsp;spipefd,&nbsp;ssize_t&nbsp;(*userfunc)(int&nbsp;,&nbsp;const&nbsp;void&nbsp;*,&nbsp;size-t&nbsp;&nbsp;<BR>));&nbsp;&nbsp;<BR>&nbsp;返回:若成功为文件描述符,出错&lt;0&nbsp;&nbsp;<BR>_______________________________________________________________________&nbsp;&nbsp;<BR>______&nbsp;&nbsp;<BR>当一个进程(通常是一个服务器)希望将一个描述符传送给另一个进程时,它调用se&nbsp;&nbsp;<BR>nd_fd或send_err。等待接收描述符的进程(客户)调用recv_fd。&nbsp;&nbsp;<BR>Send_fd经由流管道spipefd发送描述符filedes。send_err&nbsp;经由流管道spipefd发&nbsp;&nbsp;<BR>

⌨️ 快捷键说明

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