1. 程式人生 > >管道和命名管道

管道和命名管道

for ram 足夠 如果 復制 表示 pes title printf

命名管道(named PIPE)

由於基於fork機制,所以管道只能用於父進程和子進程之間,或者擁有相同祖先的兩個子進程之間 (有親緣關系的進程之間)。為了解決這一問題,Linux提供了FIFO方式連接進程。FIFO又叫做命名管道(named PIPE)。

FIFO (First in, First out)為一種特殊的文件類型,它在文件系統中有對應的路徑。當一個進程以讀(r)的方式打開該文件,而另一個進程以寫(w)的方式打開該文件,那麽內核 就會在這兩個進程之間建立管道,所以FIFO實際上也由內核管理,不與硬盤打交道。之所以叫FIFO,是因為管道本質上是一個先進先出的隊列數據結構,最 早放入的數據被最先讀出來,從而保證信息交流的順序。FIFO只是借用了文件系統(file system,命名管道是一種特殊類型的文件,因為Linux 中所有事物都是文件,它在文件系統中以文件名的形式存在。)來為管道命名。寫模式的進程向FIFO文件中寫入,而讀模式的進程從FIFO文件中讀出。當刪 除FIFO文件時,管道連接也隨之消失。FIFO的好處在於我們可以通過文件的路徑來識別管道,從而讓沒有親緣關系的進程之間建立連接

函數原型:

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *filename, mode_t mode);
int mknode(const char *filename, mode_t mode | S_IFIFO, (dev_t) 0 );

其中pathname是被創建的文件名稱,mode表示將在該文件上設置的權限位和將被創建的文件類型(在此情況下為S_IFIFO),dev是當創建設備特殊文件時使用的一個值。因此,對於先進先出文件它的值為0。

技術分享圖片
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
int main(void)
{
    char buf[80];
    int fd;
    unlink("zieckey_fifo");
    mkfifo("zieckey_fifo",0777);
    if(fork()>0)
    {
        char s[]="Hello!\n";
        fd=open("zieckey_fifo",O_WRONLY);
        write(fd,s,sizeof(s));
        //close(fd);
    }
    else
    {
        fd=open("zieckey_fifo",O_RDONLY);
        read(fd,buf,sizeof(buf));
        printf("Themessagefromthepipeis:%s\n",buf);
        //close(fd);
    }
    return  0;
}
/*執行結果為
Themessagefromthepipeis:Hello!
並且可以在程序執行目錄生成管道文件zieckey_fifo
*/
                              
技術分享圖片

註意:ls命令的輸出結果中的第一個字符為p,表示這是一個管道。最後的|符號是由ls命令的-F選項添加的,它也表示是這是一個管道。

FIFO讀寫規則

1.從FIFO中讀取數據: 約定:如果一個進程為了從FIFO中讀取數據而阻塞打開了FIFO,那麽稱該進程內的讀操作為設置了阻塞標誌的讀操作

2.從FIFO中寫入數據: 約定:如果一個進程為了向FIFO中寫入數據而阻塞打開FIFO,那麽稱該進程內的寫操作為設置了阻塞標誌的寫操作。

1.FIFO中讀取數據:

約定:如果一個進程為了從FIFO中讀取數據而阻塞打開了FIFO,那麽稱該進程內的讀操作為設置了阻塞標誌的讀操作。

(1)如果有進程寫打開FIFO,且當前FIFO為空,則對於設置了阻塞標誌的讀操作來說,將一直阻塞下去,直到有數據可以讀時才繼續執行;對於沒有設置阻塞標誌的讀操作來說,則返回0個字節,當前errno值為EAGAIN,提醒以後再試。

(2)對於設置了阻塞標誌的讀操作來說,造成阻塞的原因有兩種:一、當前FIFO內有數據,但有其它進程在讀這些數據;二、FIFO本身為空。

解阻塞的原因是:FIFO中有新的數據寫入,不論寫入數據量的大小,也不論讀操作請求多少數據量,只要有數據寫入即可。

(3)讀打開的阻塞標誌只對本進程第一個讀操作施加作用,如果本進程中有多個讀操作序列,則在第一個讀操作被喚醒並完成讀操作後,其它將要執行的讀操作將不再阻塞,即使在執行讀操作時,FIFO中沒有數據也一樣(此時,讀操作返回0)。

(4)如果沒有進程寫打開FIFO,則設置了阻塞標誌的讀操作會阻塞。

(5)如果FIFO中有數據,則設置了阻塞標誌的讀操作不會因為FIFO中的字節數少於請求的字節數而阻塞,此時,讀操作會返回FIFO中現有的數據量。

2.FIFO中寫入數據:

約定:如果一個進程為了向FIFO中寫入數據而阻塞打開FIFO,那麽稱該進程內的寫操作為設置了阻塞標誌的寫操作。

FIFO的長度是需要考慮的一個很重要因素。系統對任一時刻在一個FIFO中可以存在的數據長度是有限制的。它由#define PIPE_BUF定義,在頭文件limits.h中。在Linux和許多其他類UNIX系統中,它的值通常是4096字節,Red Hat Fedora9下是4096,但在某些系統中它可能會小到512字節。

雖然對於只有一個FIFO寫進程和一個FIFO的讀進程而言,這個限制並不重要,但只使用一個FIFO並允許多個不同進程向一個FIFO讀進程發送請求的情況是很常見的。如果幾個不同的程序嘗試同時向FIFO寫數據,能否保證來自不同程序的數據塊不相互交錯就非常關鍵了à也就是說,每個寫操作必須“原子化”。

一、對於設置了阻塞標誌的寫操作:

(1)當要寫入的數據量不大於PIPE_BUF時,Linux將保證寫入的原子性。如果此時管道空閑緩沖區不足以容納要寫入的字節數,則進入睡眠,直到當緩沖區中能夠容納要寫入的字節數時,才開始進行一次性寫操作。即寫入的數據長度小於等於PIPE_BUF時,那麽或者寫入全部字節,或者一個字節都不寫入,它屬於一個一次性行為,具體要看FIFO中是否有足夠的緩沖區。

(2)當要寫入的數據量大於PIPE_BUF時,Linux將不再保證寫入的原子性。FIFO緩沖區一有空閑區域,寫進程就會試圖向管道寫入數據,寫操作在寫完所有請求寫的數據後返回。

二、對於沒有設置阻塞標誌的寫操作:

(1)當要寫入的數據量不大於PIPE_BUF時,Linux將保證寫入的原子性。如果當前FIFO空閑緩沖區能夠容納請求寫入的字節數,寫完後成功返回;如果當前FIFO空閑緩沖區不能夠容納請求寫入的字節數,則返回EAGAIN錯誤,提醒以後再寫。

(2)當要寫入的數據量大於PIPE_BUF時,Linux將不再保證寫入的原子性。在寫滿所有FIFO空閑緩沖區後,寫操作返回。

3.為了對FIFO讀寫規則驗證:

下面提供了兩個對FIFO的讀寫程序,適當調節程序中的很少地方或命令行參數就可以對各種FIFO讀寫規則進程驗證(

管道和命名管道