<fieldset id='4ny1c'></fieldset>
<acronym id='4ny1c'><em id='4ny1c'></em><td id='4ny1c'><div id='4ny1c'></div></td></acronym><address id='4ny1c'><big id='4ny1c'><big id='4ny1c'></big><legend id='4ny1c'></legend></big></address>

      <span id='4ny1c'></span>

      <code id='4ny1c'><strong id='4ny1c'></strong></code>
      1. <tr id='4ny1c'><strong id='4ny1c'></strong><small id='4ny1c'></small><button id='4ny1c'></button><li id='4ny1c'><noscript id='4ny1c'><big id='4ny1c'></big><dt id='4ny1c'></dt></noscript></li></tr><ol id='4ny1c'><table id='4ny1c'><blockquote id='4ny1c'><tbody id='4ny1c'></tbody></blockquote></table></ol><u id='4ny1c'></u><kbd id='4ny1c'><kbd id='4ny1c'></kbd></kbd>
      2. <ins id='4ny1c'></ins>

        1. <i id='4ny1c'><div id='4ny1c'><ins id='4ny1c'></ins></div></i>
        2. <i id='4ny1c'></i>

          <dl id='4ny1c'></dl>

          Linux环境进程间通信:管道及有名管道

          • 时间:
          • 浏览:9
          • 来源:124软件资讯网

              管道及著名管道

              在本系列序中作者概述了 linux 历程间通讯的几种主要手段  。其中管道和著名管道是最早的历程间通讯机制之一  ,管道可用于具有亲缘关系历程间的通讯  ,著名管道战胜了管道没著名字的限制  ,因此  ,除具有管道所具有的功效外  ,它还允许无亲缘关系历程间的通讯  。 认清管道和著名管道的读写规则是在法式中应用它们的要害 ,本文在详细讨论了管道和著名管道的通讯机制的基础上 ,用实例对其读写规则举行了法式验证  ,这样做有利于增强读者对读写规则的感性熟悉  ,同时也提供了应用规范  。

              1、 管道概述及相关API应用

              1.1 管道相关的要害观点

              管道是Linux支持的最初Unix IPC形式之一  ,具有以下特点:

              管道是半双工的  ,数据只能向一个偏向流动;需要双方通讯时  ,需要建设起两个管道;

              只能用于父子历程或者兄弟历程之间(具有亲缘关系的历程);

              单独组成一种自力的文件系统:管道对于管道两头的历程而言  ,就是一个文件  ,但它不是通俗的文件  ,它不属于某种文件系统 ,而是自主门户 ,单独组成一种文件系统  ,而且只存在与内存中  。

              数据的读出和写入:一个历程向管道中写的内容被管道另一端的历程读出  。写入的内容每次都添加在管道缓冲区的末尾 ,而且每次都是从缓冲区的头部读出数据  。

              1.2管道的建立:

              #include int pipe(int fd[2])

              该函数建立的管道的两头处于一个历程中心  ,在现实应用中没有太大意义  ,因此  ,一个历程在由pipe()建立管道后  ,一样平常再fork一个子历程  ,然后通过管道实现父子历程间的通讯(因此也不难推出  ,只要两个历程中存在亲缘关系  ,这里的亲缘关系指的是具有配合的祖先  ,都可以接纳管道方式来举行通讯) 。

              1.3管道的读写规则:

              管道两头可划分用形貌字fd[0]以及fd[1]来形貌  ,需要注重的是  ,管道的两头是牢固了使命的  。即一端只能用于读 ,由形貌字fd[0]表现 ,称其为管道读端;另一端则只能用于写  ,由形貌字fd[1]来表现  ,称其为管道写端  。若是试图从管道写端读取数据  ,或者向管道读端写入数据都将导致错误发生  。一样平常文件的I/O函数都可以用于管道  ,如close、read、write等等  。

              从管道中读取数据:

              若是管道的写端不存在 ,则以为已经读到了数据的末尾  ,读函数返回的读出字节数为0;

              当管道的写端存在时 ,若是请求的字节数目大于PIPE_BUF  ,则返回管道中现有的数据字节数  ,若是请求的字节数目不大于PIPE_BUF ,则返回管道中现有数据字节数(此时  ,管道中数据量小于请求的数据量);或者返回请求的字节数(此时  ,管道中数据量不小于请求的数据量)  。注:(PIPE_BUF在include/linux/limits.h中界说 ,差别的内核版本可能会有所差别  。Posix.1要求PIPE_BUF至少为512字节  ,red hat 7.2中为4096)  。

              关于管道的读规则验证:

              #include #include

              向管道中写入数据:

              向管道中写入数据时  ,linux将不保证写入的原子性 ,管道缓冲区一有空闲区域  ,写历程就会试图向管道写入数据 。若是读历程不读走管道缓冲区中的数据 ,那么写操作将一直壅闭  。

              注:只有在管道的读端存在时  ,向管道中写入数据才有意义 。否则 ,向管道中写入数据的历程将收到内核传来的SIFPIPE信号  ,应用法式可以处置惩罚该信号  ,也可以忽略(默认行动则是应用法式终止) 。

              对管道的写规则的验证1:写端对读端存在的依赖性

              #include #include main(){ int pipe_fd[2]; pid_t

              则输出效果为: Broken pipe,缘故原由就是该管道以及它的所有fork()产物的读端都已经被关闭  。若是在父历程中保留读端  ,即在写完pipe后  ,再关闭父历程的读端 ,也会正常写入pipe  ,读者可自己验证一下该结论 。因此  ,在向管道写入数据时 ,至少应该存在某一个历程  ,其中管道读端没有被关闭  ,否则就会泛起上述错误(管道断裂,历程收到了SIGPIPE信号  ,默认行动是历程终止)

              对管道的写规则的验证2:linux不保证写管道的原子性验证

              #include #include #include main(int argc

              结论:

              写入数目小于4096时写入是非原子的!

              若是把父历程中的两次写入字节数都改为5000 ,则很容易得出下面结论:

              写入管道的数据量大于4096字节时  ,缓冲区的空闲空间将被写入数据(补齐)  ,直到写完所有数据为止  ,若是没有历程读数据  ,则一直壅闭 。

              1.4管道应用实例:

              实例一:用于shell

              管道可用于输入输出重定向 ,它将一个下令的输出直接定向到另一个下令的输入  。好比 ,当在某个shell法式(Bourne shell或C shell等)键入who│wc -l后  ,响应shell法式将建立who以及wc两个历程和这两个历程间的管道  。思量下面的下令行:

              $kill -l 运行效果见附一  。

              $kill -l | grep SIGRTMIN 运行效果如下:

              30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+134) SIGRTMIN+2 35) SIGRTMIN

              实例二:用于具有亲缘关系的历程间通讯

              下面例子给出了管道的详细应用  ,父历程通过管道发送一些下令给子历程  ,子历程剖析下令 ,并凭据下令作响应处置惩罚 。

              #include #include main(){ int pipe_fd[2]; pid_t

              1.5管道的局限性

              管道的主要局限性正体现在它的特点上:

              只支持单向数据流;

              只能用于具有亲缘关系的历程之间;

              没著名字;

              管道的缓冲区是有限的(管道制存在于内存中  ,在管道建立时  ,为缓冲区分配一个页面巨细);

              管道所传送的是无花样字节省  ,这就要求管道的读出方和写入方必须事先约定好数据的花样 ,好比几多字节算作一个新闻(或下令、或记载)等等;

              2、 著名管道概述及相关API应用

              2.1 著名管道相关的要害观点

              管道应用的一个重大限制是它没著名字 ,因此  ,只能用于具有亲缘关系的历程间通讯  ,在著名管道(named pipe或FIFO)提出后 ,该限制获得了战胜 。FIFO差别于管道之处在于它提供一个路径名与之关联  ,以FIFO的文件形式存在于文件系统中  。这样  ,纵然与FIFO的建立历程不存在亲缘关系的历程  ,只要可以会见该路径 ,就能够相互通过FIFO相互通讯(能够会见该路径的历程以及FIFO的建立历程之间)  ,因此  ,通过FIFO不相关的历程也能交流数据 。值得注重的是  ,FIFO严酷遵照先进先出(first in first out)  ,对管道及FIFO的读总是从最先处返回数据 ,对它们的写则把数据添加到末尾  。它们不支持诸如lseek()等文件定位操作  。

              2.2著名管道的建立

              #include #include int mkfifo(const char * pathname, mode_t mode)

              该函数的第一个参数是一个通俗的路径名  ,也就是建立后FIFO的名字  。第二个参数与打开通俗文件的open()函数中的mode 参数相同  。若是mkfifo的第一个参数是一个已经存在的路径名时  ,会返回EEXIST错误  ,以是一样平常典型的挪用代码首先会检查是否返回该错误  ,若是确实返回该错误 ,那么只要挪用打开FIFO的函数就可以了  。一样平常文件的I/O函数都可以用于FIFO  ,如close、read、write等等  。

              2.3著名管道的打开规则

              著名管道比管道多了一个打开操作:open  。

              FIFO的打开规则:

              若是当前打开操作是为读而打开FIFO时 ,若已经有响应历程为写而打开该FIFO  ,则当前打开操作将乐成返回;否则  ,可能壅闭直到有响应历程为写而打开该FIFO(当前打开操作设置了壅闭标志);或者  ,乐成返回(当前打开操作没有设置壅闭标志)  。

              若是当前打开操作是为写而打开FIFO时 ,若是已经有响应历程为读而打开该FIFO  ,则当前打开操作将乐成返回;否则  ,可能壅闭直到有响应历程为读而打开该FIFO(当前打开操作设置了壅闭标志);或者  ,返回ENXIO错误(当前打开操作没有设置壅闭标志) 。

              对打开规则的验证参见附2  。

              2.4著名管道的读写规则

              从FIFO中读取数据:

              约定:若是一个历程为了从FIFO中读取数据而壅闭打开FIFO ,那么称该历程内的读操作为设置了壅闭标志的读操作  。

              若是有历程写打开FIFO  ,且当前FIFO内没有数据  ,则对于设置了壅闭标志的读操作来说 ,将一直壅闭  。对于没有设置壅闭标志读操作来说则返回-1 ,当前errno值为EAGAIN  ,提醒以后再试  。

              对于设置了壅闭标志的读操作说  ,造成壅闭的缘故原由有两种:当前FIFO内有数据 ,但有其它历程在读这些数据;另外就是FIFO内没有数据 。解壅闭的缘故原由则是FIFO中有新的数据写入  ,岂论信写入数据量的巨细  ,也岂论读操作请求几多数据量  。

              读打开的壅闭标志只对本历程第一个读操作施加作用  ,若是本历程内有多个读操作序列  ,则在第一个读操作被叫醒并完成读操作后 ,其它将要执行的读操作将不再壅闭  ,纵然在执行读操作时  ,FIFO中没有数据也一样(此时  ,读操作返回0)  。

              若是没有历程写打开FIFO  ,则设置了壅闭标志的读操作会壅闭 。

              注:若是FIFO中有数据  ,则设置了壅闭标志的读操作不会由于FIFO中的字节数小于请求读的字节数而壅闭  ,此时  ,读操作会返回FIFO中现有的数据量  。

              向FIFO中写入数据:

              约定:若是一个历程为了向FIFO中写入数据而壅闭打开FIFO  ,那么称该历程内的写操作为设置了壅闭标志的写操作  。

              对于设置了壅闭标志的写操作:

              当要写入的数据量不大于PIPE_BUF时  ,linux将保证写入的原子性  。若是此时管道空闲缓冲区不足以容纳要写入的字节数  ,则进入睡眠  ,直到当缓冲区中能够容纳要写入的字节数时  ,才最先举行一次性写操作  。

              当要写入的数据量大于PIPE_BUF时 ,linux将不再保证写入的原子性  。FIFO缓冲区一有空闲区域  ,写历程就会试图向管道写入数据  ,写操作在写完所有请求写的数据后返回 。

              对于没有设置壅闭标志的写操作:

              当要写入的数据量大于PIPE_BUF时  ,linux将不再保证写入的原子性  。在写满所有FIFO空闲缓冲区后 ,写操作返回 。

              当要写入的数据量不大于PIPE_BUF时  ,linux将保证写入的原子性  。若是当前FIFO空闲缓冲区能够容纳请求写入的字节数  ,写完后乐成返回;若是当前FIFO空闲缓冲区不能够容纳请求写入的字节数 ,则返回EAGAIN错误  ,提醒以后再写;

              对FIFO读写规则的验证:

              下面提供了两个对FIFO的读写法式  ,适当调治法式中的很少地方或者法式的下令行参数就可以对种种FIFO读写规则举行验证 。

              法式1:写FIFO的法式

              #include #include #include #include

              法式应用说明:

              把读法式编译成两个差别版本:

              壅闭读版本:br

              以及非壅闭读版本nbr

              把写法式编译成两个四个版本:

              非壅闭且请求写的字节数大于PIPE_BUF版本:nbwg

              非壅闭且请求写的字节数不大于PIPE_BUF版本:版本nbw

              壅闭且请求写的字节数大于PIPE_BUF版本:bwg

              壅闭且请求写的字节数不大于PIPE_BUF版本:版本bw

              下面将使用br、nbr、w取代响应法式中的壅闭读、非壅闭读

              验证壅闭写操作:

              当请求写入的数据量大于PIPE_BUF时的非原子性:

              nbr 1000

              bwg

              当请求写入的数据量不大于PIPE_BUF时的原子性:

              nbr 1000

              bw

              验证非壅闭写操作:

              当请求写入的数据量大于PIPE_BUF时的非原子性:

              nbr 1000

              nbwg

              请求写入的数据量不大于PIPE_BUF时的原子性:

              nbr 1000

              nbw

              不管写打开的壅闭标志是否设置  ,在请求写入的字节数大于4096时  ,都不保证写入的原子性 。但二者有本质区别:

              对于壅闭写来说 ,写操作在写满FIFO的空闲区域后  ,会一直等候  ,直到写完所有数据为止  ,请求写入的数据最终都市写入FIFO;

              而非壅闭写则在写满FIFO的空闲区域后  ,就返回(现实写入的字节数) ,以是有些数据最终不能够写入 。

              对于读操作的验证则比力简朴  ,不再讨论 。

              2.5著名管道应用实例

              在验证了响应的读写规则后  ,应用实例似乎就没有须要了 。

              小结:

              管道常用于两个方面:(1)在shell中时常会用到管道(作为输入输入的重定向) ,在这种应用方式下  ,管道的建立对于用户来说是透明的;(2)用于具有亲缘关系的历程间通讯  ,用户自己建立管道 ,并完成读写操作  。

              FIFO可以说是管道的推广  ,战胜了管道无名字的限制  ,使得无亲缘关系的历程同样可以接纳先进先出的通讯机制举行通讯 。

              管道和FIFO的数据是字节省 ,应用法式之间必须事先确定特定的传输"协议"  ,接纳流传具有特定意义的新闻  。

              要天真应用管道及FIFO ,明白它们的读写规则是要害 。

              附1:kill -l 的运行效果  ,显示了当前系统支持的所有信号:

              1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL5) SIGTRAP 6) SIGABRT

              除了在此处用来说明管道应用外 ,接下来的专题还要对这些信号分类讨论  。

              附2:对FIFO打开规则的验证(主要验证写打开对读打开的依赖性)