IPC
前面總結了匿名管道,現在來看命名管道:由於匿名管道的一個限制就是:只能是有血緣關系的進程間才可以通信,比如:有兩個同祖先的子進程,父子進程等;為了突破這一個限制,想讓沒有任何關系的兩個進程間也能正常通信,所以就就有了命名管道這樣的一個通信機制,一起來看看:
命名管道
一、原理:
管道的一個不足之處是沒有名字,因此,只能用於具有親緣關系的進程間通信,在命名管道(named pip或FIFO)提出后,該限制得到了克服。FIFO不同於管道之處在於它提供一個路徑名與之關聯,以FIFO的文件形式存儲於文件系統中。命名管道是一個設備文件,因此,即使進程與創建FIFO的進程不存在親緣關系,只要可以訪問該路徑,就能夠通過FIFO相互通信。
值得注意的是,FIFO(first input first output)總是按照先進先出的原則工作,第一個被寫入的數據將首先從管道中讀出。
Linux下有兩種方式創建命名管道。一是在Shell下交互地建立一個命名管道,二是在程序中使用系統函數建立命名管道。Shell方式下可使用mknod或mkfifo命令,下面命令使用 mknod創建了一個命名管道:
mknod namedpipe
創建命名管道的系統函數有兩個:mknod和mkfifo。兩個函數均定義在頭⽂文件sys/stat.h,
函數原型如下:
#include <sys/types.h> #include <sys/stat.h> int mknod(const char *path,mode_t mod,dev_t dev); int mkfifo(const char *path,mode_t mode);
函數mknod參數中path為創建的命名管道的全路徑名:mod為創建的命名管道的模式,指明其存取權限;dev為設備值,該值取決於文件創建的種類,它只在創建設備文件時才會用到。這兩個函數調用成功都返回0,失敗都返回-1。
三、實例
用mkfifo創建命名管道:


“S_IFIFO|0666”指明創建一個命名管道且存取權限為0666,即創建者、與創建者同組的用戶、其他用戶對該命名管道的訪問權限都是可讀可寫。
命名管道創建后就可以使用了,命名管道和管道的使用方法基本是相同的。只是使用命名管道時,必須用open()將其打開。因為命名管道是一個存在於硬盤上的文件,而管道是存在於內存中的特殊文件。
需要注意的是,調用open()打開命名管道的進程可能會被阻塞。但如果同時用讀寫方式(O_RDWR)打開,則一定不會導致阻塞;如果以只讀方式(O_RDONLY)打開,則調用open()函數的進程將會被阻塞直到有寫方打開管道;同樣以寫方式(O_WRONLY)打開也會阻塞直到有讀方式打開管道。
四:結束
文件系統中的路徑名是全局的,各進程都可以訪問,因此可以用文件系統中的路徑名來標識一個IPC通道。 命名管道也被稱為FIFO文件,它是一種特殊類型的文件,它在文件系統中以文件名的形式存在,但是它的行為卻和之前所講的沒有名字的管道(匿名管道)類似。
由於Linux中所有的事物都可被視為文件,所以對命名管道的使用也就變得與文件操作非常的統一,也使它的使用非常方便,同時我們也可以像平常的文件名一樣在命令中使用。
前面的例子兩個進程之間的通信問題,也就是說,一個進程向FIFO文件寫數據,而另一個進程則在FIFO文件中讀取數據。試想這樣一個問題,只使用一個FIFO文件,如果有多個進程同時向同一個FIFO文件寫數據,而只有一個讀FIFO進程在同一個FIFO文件中讀取數據時,會發生怎么樣的情況呢,會發生數據塊的相互交錯是很正常的?而且個人認為多個不同進程向一個FIFO讀進程發送數據是很普通的情況。
為了解決這一問題,就是讓寫操作的原子化。怎樣才能使寫操作原子化呢?答案很簡單,系統規定:在一個以O_WRONLY(即阻塞方式)打開的FIFO中, 如果寫入的數據長度小於等待PIPE_BUF,那么或者寫入全部字節,或者一個字節都不寫入。如果所有的寫請求都是發往一個阻塞的FIFO的,並且每個寫記請求的數據長度小於等於PIPE_BUF字節,系統就可以確保數據決不會交錯在一起。
命名管道總結到此,其余通信機制,見下一篇博文。
賜教!
