Linux程序通訊 有名管道

2021-08-31 11:39:24 字數 4301 閱讀 1435

管道(pipe)是無名管道,他是程序資源的一部分,隨著程序的結束而消失。並且它只能在擁有公共祖先程序的程序內通訊。而有名管道(fifo)的出現則解決了這個問題。fifo提供了乙個路徑名與它關聯。這樣可以通過訪問該路徑就能使得兩個程序之間相互通訊。此處的fifo嚴格遵守「先進先出」原則。讀總是從頭開始的,寫總是從尾部進行的。匿名管道和fifo都不支援lseek函式對他們操作。linux下建立有名管道的函式是mkfifo。

函式原型: int mkfifo(const char * pathname,mode_t mode);

函式功能:建立乙個fifo檔案,用於程序之間的通訊。pathname就是路徑名,mode是該檔案的許可權。返回值表示是否成功,返回0表示成功,返回-1表示失敗,失敗原因在errno中。(建立fifo的時候,要求不存在這樣的fifo)。

和pipe建立匿名管道相比,mkfifo需要設定檔案許可權。這是因為pipe建立的匿名管道是核心借助緩衝區建立的,它不在磁碟上真實存在,只在記憶體中存在。而mkfifo建立的有名管道是在磁碟上真實存在的,因此需要檔案許可權,正是由於真實存在這樣乙個檔案,所以才克服了在任意程序間通訊的問題。

例如執行下面**來建立乙個fifo。

可以看到,它以p開頭,表示它是乙個fifo檔案。它是真實存在於磁碟上的,不僅僅在記憶體中。程序結束了這個檔案仍然在。fifo和匿名管道一樣,預設下要考慮阻塞。

當使用o_nonblock標誌的時候,開啟fifo檔案,讀取操作會立即返回。但是如果沒有程序讀取fifo檔案,那麼寫入fifo的操作會返回enxio錯誤**。

不使用o_nonblock標誌時,開啟fifo的操作必須等待其他程序寫入fifo後才執行,當然寫入fifo的操作也必須等到其他程序來讀取fifo以後才能執行。

當存在這個fifo檔案的時候,再次建立這個fifo會顯示file exists。

首先,第一種情形的測試。

#include#include#include#include#include#includeint main()

pid_t pid;

pid = fork();

if(0 < pid)

else

exit(0);

}if(0 == pid)

if(-1 == pid)

return 0;

}

執行結果如下:

可以看到會發生錯誤,因為它沒有阻塞。那麼接著試一下直接讀乙個fifo檔案,看看會發生什麼。

#include#include#include#include#include#includeint main()

; ret = mkfifo("my_fifo",0666);

if(0 != ret)

pid_t pid;

pid = fork();

if(0 < pid)

else

exit(0);

}if(0 == pid)

if(-1 == pid)

return 0;

}

看到的結果是對乙個空的fifo檔案開啟並執行read操作是沒有問題的。

先以唯讀方式開啟,如果沒有程序已經為寫而開啟乙個 fifo, 唯讀 open() 成功,並且 open() 不阻塞。

下面,當不設定o_nonblock標誌的時候,fifo和匿名管道的處理方式是一樣的。管道這個名字是非常形象的,乙個管道必須有兩端(就是在乙個程序中必須讀,另乙個程序必須寫),只有這樣,才能正常操作,否則程序將會阻塞。例如下面這樣。

#include#include#include#include#include#include#includeint main()

; ret = mkfifo("my_fifo",0666);

if(0 != ret)

pid_t pid;

pid = fork();

if(0 < pid)

else

wait(null);

exit(0);

}if(0 == pid)

if(-1 == pid)

return 0;

}

我們僅僅在父程序中進行了寫(write),沒有其他程序在讀(read)。這樣造成的結果是程序一直阻塞在這裡,如下

沒有輸出結果,阻塞在這裡不動了。而當我們加上注釋掉了那兩句話以後,程式就會有輸出,結果如下:

或者說,這也體現了程序的並發行,管子有了一端以後,還必須有另一端,這才能構成管道。

上述的情形都是在唯讀或者只寫下開啟fifo檔案而言的,如果使用o_rdwr開啟fifo檔案,那麼除了read空fifo會阻塞。其餘將不會有問題。

測試一下,fifo用於兩個無關程序直接的通訊。首先建立我們有兩個程序,乙個是test1,另乙個是test2.

//test1的源**

//test1是寫fifo

#include#include#include#include#include#includeint main()

; ret = mkfifo("fifo",0666); 中建立fifo檔案

fd = open("fifo",o_wronly); //只寫方式開啟

write(fd,str,5);

close(fd);

return 0;

}

//test2的源**

//test2是讀fifo

#include#include#include#include#include#includeint main()

; fd = open("fifo",o_rdonly);

read(fd,str,5);

printf("%s\n",str);

close(fd);

return 0;

}

我們把test1和test2的源**生成可執行檔案後,開啟兩個終端。如果我先執行test1,然後執行test2.那麼test2將讀取到fifo中的資料。如下所示。

我們沒有設定o_nonblock,先執行test1之後,會發現test1阻塞在這裡。等我們把test2也執行了之後,test1不在阻塞,執行結束,然後test2也成功列印出了hello。

換個執行順序,我們先執行test2,然後執行test1.這樣會發現test2阻塞在這裡。等我們把test1也執行了之後,test2不在阻塞,向螢幕列印hello.

如果我們不想讓fifo阻塞,那麼開啟檔案的時候設定為可讀可寫即可

fd = open("fifo", o_rdwr);
當然,如果fifo是空的,那麼即使設定了可讀可寫,read()操作仍舊會阻塞。這樣的執行結果和上面所說的是一致的。自己執行一下才能深刻理解。這裡不好用說明。

呼叫 write() 函式向 fifo 裡寫資料,當緩衝區已滿時 write() 也會阻塞。

首先使用mkfifo命令建立乙個fifo檔案,然後將ls的輸出重定向到myfifo。

可以看到阻塞在了這裡,我們現在開啟另外乙個終端,輸入cat myfifo。

這樣就將ls的結果列印出來了,同時另外乙個終端也不再阻塞。

Linux程序通訊 有名管道

管道 pipe 是無名管道,他是程序資源的一部分,隨著程序的結束而消失。並且它只能在擁有公共祖先程序的程序內通訊。而有名管道 fifo 的出現則解決了這個問題。fifo提供了乙個路徑名與它關聯。這樣可以通過訪問該路徑就能使得兩個程序之間相互通訊。此處的fifo嚴格遵守 先進先出 原則。讀總是從頭開始...

程序通訊 有名管道

無名管道只能由父子程序使用 但是通過命名管道,不相關的程序也能交換資料。建立管道mkfifo 開啟管道open 讀管道read 寫管道write 關閉管道close 刪除管道unlink 函式作用 建立有名管道 函式原型 int mkfifo const char pathname,mode t m...

Linux程序通訊之有名管道

1 定義參照前文無名管道 2 特點 1 區別於無名,管道有名管道可以使互不相關的兩個程序通訊 在建立管道時,通過路徑 檔名來進行識別 2 建立有名管道後,程序可以將其作為檔案來進行讀寫 3 先進先出fifo。4 fifo在寫入的資料的位元組數小於或者等於pipe buf時,能夠保證write操作是原...