這裡介紹程序的另一種通訊方式——命名管道,來解決不相關程序間的通訊問題。
一、什麼是命名管道
命名管道也被稱作fifo檔案,它是一種特殊型別的檔案,它在檔案系統中以檔名的形式存在,但是它的行為卻和之前所講的沒有名字的管道(匿名管道)類似。
由於linux中所有的事物都可被視為檔案,所以對命名管道的使用也就變得與檔案操作非常的統一,也使它的使用非常方便,同時我們也可以像平常的檔名一樣在命令中使用。
二、建立命名管道
我們可以使用下面兩函式之一來建立乙個命名管道,它們的原型如下:
#include
#include
int mkfifo(const char* filename,mode_t mode);
int mknod(const char* filename,mode_t mode | s_ififo,(dev_t)0);
這兩個函式都能建立乙個fifo檔案,注意是建立乙個真實存在於檔案系統中的檔案,filename指定了檔名,而mode則指定了檔案的讀寫許可權。
mknod是比較老的函式,而使用mkfifo函式更加簡單和規範,所以建議在可能的情況下,盡量使用mkfifo而不是mknod。
三、訪問命名管道
1、開啟fifo檔案
與開啟其他檔案一樣,fifo檔案也可以使用open呼叫來開啟。注意,mkfifo函式只是建立乙個fifo檔案,要使用命名管道還是將其開啟。
但是有兩點要注意,1、就是程式不能以o_rdwr模式開啟fifo檔案進行讀寫操作,而其行為也未明確定義,因為如乙個管道以讀/寫方式開啟,程序就會讀回自己的輸出,同時我們通常使用fifo只是為了單向的資料傳遞。2、就是傳遞給open呼叫的是fifo的路徑名,而不是正常的檔案。
開啟fifo檔案通常有四種方式:
1、open(const char* path,o_rdonly);
2、open(const char* path,o_rdonly | o_nonblock);
3、open(const char* path,o_wronly);
4、open(const char* path,o_wronly | o_nonblock);
在open函式呼叫第二個引數中,看到乙個陌生的選項o_nonblock,選項o_nonblock表示非阻塞,加上這個選項後,表示open呼叫是非阻塞的,如果麼有這個選項,則表示open呼叫是阻塞的。
open呼叫阻塞是什麼一回事呢?很簡單,對於以唯讀方式(o_rdonly)開啟的fifo檔案,如果open呼叫是阻塞的(即第二個引數為o_rdonly),除非有乙個程序以寫方式開啟同乙個fifo,否則它不會返回;如果open呼叫是非阻塞的(即第二個引數為o_rdonly | o_nonblock),則即使沒有其他程序以寫方式開啟同乙個fifo檔案,open呼叫將成功並立即返回。
對於以只寫方式(o_wronly)開啟的fifo檔案,如果open呼叫是阻塞的(即第二個引數為o_wronly),open呼叫將被阻塞,直到有乙個程序以唯讀方式開啟同乙個fifo檔案為止;如果open呼叫是非阻塞的(即第二個引數為o_wronly | o_nonblock),open總會立即返回,但如果沒有其他程序以唯讀方式開啟同乙個fifo檔案,open呼叫將返回-1,並且fifo也不會被開啟。
四、使用fifo實現程序間的通訊
說了這麼多,下面就用乙個例子程式來說明一下,兩個程序如何通過fifo實現通訊吧。這裡有兩個原始檔,乙個fifowrite.c,它在需要時建立管道,然後向管道寫入資料,資料由檔案data.txt提供,大小為10m,內容全是字元『0』。另乙個原始檔為fiforead.c,它從fifo中讀取資料,並把讀到的資料儲存到另乙個檔案dataformfifo.txt中。為了讓程式更加簡潔,忽略了有些函式呼叫是否成功的檢查。
write fifo原始碼:
#include
#include
#include
#include
#include
#include
#include
#include
#define fifo_file "/tmp/fifo_test"
int main(int argc,char* ar**)
;if(access(fifo_file,f_ok ) == -1)
}filefd = open("./test_lock.txt",o_rdonly);
if(filefd == -1)
pipefd = open(fifo_file,o_wronly);
if(pipefd == -1)
readbytes = read(filefd,buffer,pipe_buf);
while(readbytes > 0)
close(filefd);
close(pipefd);
return 0;
}read fifo原始碼:
#include
#include
#include
#include
#include
#include
#include
#include
#define fifo_file "/tmp/fifo_test"
int main(int argc,char* ar**)
;int readbytes = 0;
int filefd,pipefd;
if(access(fifo_file,f_ok) == -1)
}filefd = open("./test_lock_tmp.txt",o_wronly | o_creat);
if(filefd == -1)
pipefd = open(fifo_file,o_rdonly);
}readbytes = read(pipefd,buffer,pipe_buf);
while(readbytes > 0)
close(filefd);
close(pipefd);
return 0;
}五、命名管道的安全問題
前面的例子是兩個程序之間的通訊問題,也就是說,乙個程序向fifo檔案寫資料,而另一程序則在fifo檔案中讀取資料。試想這樣乙個問題,只使用乙個fifo檔案,若有多個程序同時向同乙個fifo檔案寫資料,而只有乙個讀fifo程序在同乙個fifo檔案中讀取資料時,會發生什麼情況呢,會發生資料塊的相互交錯是很正常的?而且個人認為多個不同程序向乙個fifo讀程序傳送資料是很普遍的情況。
為解決這一問題,就是讓寫操作原子化。怎樣使寫操作原子化呢?答案很簡單,系統規定:在乙個以o_wronly(即阻塞方式)開啟的fifo中,如果寫入的資料長度小於等待pipe_buf,那麼或者寫入全部位元組,或者乙個位元組也不寫入。如果所有的寫請求都是發往乙個阻塞的fifo的,並且每個寫請求的資料長度小於等於pipe_buf位元組,系統就可以確保資料絕不會交錯在一起。
六、命名管道與匿名管道的對比
使用匿名管道,則通訊的程序之間需要乙個父子關係,通訊的兩個程序一定是由乙個共同的祖先程序啟動。但是匿名管道沒有上面說到的資料交叉問題。
與匿名管道相比,命名管道相互通訊的兩個程序沒有必然的聯絡,若硬要說他們具有某種聯絡,就只能是它們都訪問同乙個fifo檔案。它解決了之前在匿名管道**現的通訊的兩個程序一定是由乙個共同的祖先程序啟動的問題。但是為了資料的安全,我們很多時候要取樣阻塞的fifo,讓寫操作變成原子操作。
Linux程序間通訊 命名管道
ipc 命名管道 一 原理 管道的乙個不足之處是沒有名字,因此,只能用於具有親緣關係的程序間通訊,在命名管道 named pip 或fifo 提出後,該限制得到了克服。fifo 不同於管道之處 在於它提供乙個路徑名與之關聯,以fifo的檔案形式儲存於檔案系統中 命名管道是乙個裝置檔案,因此,即使程序...
linux程序間通訊(命名管道)
在處理程序間通訊的問題時,匿名管道只能在有親緣關係的程序中進行通訊。如何做到在任意兩個程序之間通訊,這就要用到命名管道。命名管道也被稱為fifo檔案,它是一種特殊型別的檔案,在檔案系統中以檔案的形式存在,它的行為和匿名管道類似。可以使用mkfifo函式來建立乙個命名管道。int mkfifo con...
linux程序間通訊 命名管道
命名管道也被稱為fifo檔案,它是一種特殊型別的檔案,它在檔案系統中以檔名的形式存在,但是它的行為卻和之前所講的沒有名字的管道 匿名管道 類似。有名管道是有名有形的,為了使用這種管道linux中設立了乙個專門的特殊檔案系統 管道檔案,它存在於檔案系統中,任何程序可以在任何時候通過有名管道的路徑和檔案...