shell 匿名管道和命名管道


管道的特點:如果管道中沒有數據,那么取管道數據的操作就會滯留,直到管道內進入數據,然后讀出后才會終止這一操作;同理,寫入管道的操作如果沒有讀取管道的操作,這一動作也會滯留。

1,匿名管道

匿名管道使用符號 |  表示,管道的兩端時兩個普通的,匿名的,打開的文件描述符:一端只讀和一端只寫。 

cat file | less

2,命名管道

命名管道也稱FIFO,先進先出,任何進程都可以通過FIFO共享數據;除非FIFO兩端同時又讀與寫的進程,否則FIFO的數據量將會阻塞;

匿名管道和命名管道的區別:

  • 匿名管道shell自動創建,存在於內核中;FIFO是又程序創建( mkfifo 命令),存在於系統文件中;
  • 匿名管道是單向的字節流,而FIFO則是雙向的字節流。

語法:

mkfifo [ -m Mode ] Filename

Mode用於設置權限

退出狀態:

0  :成功創建所指定的FIFO特別文件

>0:發生錯誤

example2.1:

 [yuzhimin@gate02 shell_test]$ mkfifo -m 666 fifo_test2  

結果如下:

1 [yuzhimin@gate02 shell_test]$ ll fifo_test*
2 prw-rw-rw-. 1 yuzhimin zmyu 0 Mar 19 15:14 fifo_test2

example2.2:

1 [yuzhimin@gate02 shell_test]$ mkfifo -m g-w,o-rw fifo_test4
2 [yuzhimin@gate02 shell_test]$ mkfifo -m g+w fifo_test5
3 [yuzhimin@gate02 shell_test]$ ll fifo_test*
4 prw-r-----. 1 yuzhimin zmyu 0 Mar 19 15:17 fifo_test4
5 prw-rw-rw-. 1 yuzhimin zmyu 0 Mar 19 15:18 fifo_test5

 

 

 

參考資料:

https://www.cnblogs.com/xianghang123/archive/2012/03/31/2427731.html

示例

   1. 要使用許可權 prw-r–r– 創建 FIFO 特別文件,請輸入:
      mkfifo  -m 644 /tmp/myfifo
      此命令使用所有者的讀/寫許可權以及組和其他用戶的讀許可權來創建 /tmp/myfifo 文件。
   2. 使用 -(減號)操作符創建一個 FIFO 特別文件以設置 prw-r—– 許可權,請輸入:
      mkfifo  -m g-w,o-rw /tmp/fifo2
      此命令創建 /tmp/fifo2 文件,刪除組的寫權限和其他用戶的所有許可權。

          注:如果多於一個的文件是用 -(減號)操作符創建的,那么用頓號分隔每個方式說明符,中間不用空格。

文件

/usr/bin/mkfifo     包含 mkfifo 命令。

 

Linux下進程間通信:命名管道-mkfifo

 

 

IPC Linux mkfifo mknode 命名管道 進程間通信

摘要:進程間通信的方法有很多,FIFO與管道是最古老,也是相對來說更簡單的一個通信機制。FIFO相對管道有一個優勢,就是FIFO只要求兩個進程是同一主機的,而不要求進程之間存在親緣關系。FIFO是存在於文件系統的文件,可以使用諸如open、read、write等函數來操作。本文總結網絡和APUE關於FIFO討論,同時參考了Linux系統手冊。

目錄 [ 隱藏]

FIFO(命名管道)概述

FIFO是一種進程通信機制,它突破通常管道無法進行無關進程之間的通信的限制,使得同一主機內的所有的進程都可以通信。FIFO是一個文件類型,stat結構中st_mode指明一個文件結點是不是一個FIFO,可以使用宏S_ISFIFO來測試這一點。

當一個FIFO存在於文件系統里時,我們只需要在想進行通信的進程內打開這個文件就可以了。當然FIFO作為一個特殊的文件,它有一些不同普通文件特性,下面會詳細詳述它的讀寫規則,這些相對精通文件來有一定的區別。

我們可以使用open、read、write來操作FIFO文件,從而實現進程間通信的目的。在shell環境下,也可以直接使用FIFO,這時往往與重寫向有一些關聯,一般系統都提供mkfifo實用程序來創建一個FIFO文件,這個程序實際上使用mkfifo系統調用來完成這個事。

mkfifo函數

mkfifo創建一個指定名字的FIFO,它的函數原型如下:

#include<sys/stat.h>
int mkfifo(const char* pathname, mode_t mode);
返回值:成功,0;失敗,-1

 

參數pathname指出想要創建的FIFO路徑,參數mode指定創建的FIFO訪問模式。這個訪問會與當前進程的umask進程運算,以產生實際應用的權限模式。

mkfifo返回-1時表示創建過程中遇到某種錯誤,此時會設置errno,用戶可以檢測errno來取得進一步信息:

EACCES: 路徑所在的目錄不允許執行權限EEXIST:路徑已經存在,這時包括路徑是一個符號鏈接,無論它是懸空還沒有懸空。ENAMETOOLONG:要么全部的文件名大於PATH_MAX,要么是單獨的文件名大於NAME_MAX。在GNU系統里沒有這個文件名長度的限制,但在其它系統里可能存在。ENOENT:目錄部分不存在,或者是一個懸空鏈接。ENOTDIR:目錄部分不一個目錄。EROFS:路徑指向一個只讀的文件系統。

 

命名管道讀寫規則

FIFO又叫命名管道,事實上它與管道確實在下許多相似之處,下面關於規則的討論很體現這個相似。

從FIFO中讀取數據

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

如果有進程寫打開FIFO,且當前FIFO為空,則對於設置了阻塞標志的讀操作來說,將一直阻塞下去,直到有數據可以讀時才繼續執行;對於沒有設置阻塞標志的讀操作來說,則返回0個字節,當前errno值為EAGAIN,提醒以后再試。對於設置了阻塞標志的讀操作來說,造成阻塞的原因有兩種:一、當前FIFO內有數據,但有其它進程在讀這些數據;二、FIFO本身為空。
解阻塞的原因是:FIFO中有新的數據寫入,不論寫入數據量的大小,也不論讀操作請求多少數據量,只要有數據寫入即可。讀打開的阻塞標志只對本進程第一個讀操作施加作用,如果本進程中有多個讀操作序列,則在第一個讀操作被喚醒並完成讀操作后,其它將要執行的讀操作將不再阻塞,即使在執行讀操作時,FIFO中沒有數據也一樣(此時,讀操作返回0)。如果沒有進程寫打開FIFO,則設置了阻塞標志的讀操作會阻塞。如果FIFO中有數據,則設置了阻塞標志的讀操作不會因為FIFO中的字節數少於請求的字節數而阻塞,此時,讀操作會返回FIFO中現有的數據量。從FIFO中寫入數據

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

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

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

設置了阻塞標志的寫操作:

當要寫入的數據量不大於PIPE_BUF時,Linux將保證寫入的原子性。如果此時管道空閑緩沖區不足以容納要寫入的字節數,則進入睡眠,直到當緩沖區中能夠容納要寫入的字節數時,才開始進行一次性寫操作。即寫入的數據長度小於等於PIPE_BUF時,那么或者寫入全部字節,或者一個字節都不寫入,它屬於一個一次性行為,具體要看FIFO中是否有足夠的緩沖區。當要寫入的數據量大於PIPE_BUF時,Linux將不再保證寫入的原子性。FIFO緩沖區一有空閑區域,寫進程就會試圖向管道寫入數據,寫操作在寫完所有請求寫的數據后返回。

沒有設置阻塞標志的寫操作:

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

本段給出使用FIFO一個示例,它體現了兩個使用FIFO的典型情景。

創建FIFO

 1 #include<stdlib.h>
 2 #include<stdio.h>
 3 #include<sys/types.h>
 4 #include<sys/stat.h>
 5 int main()
 6 {
 7         int res = mkfifo("/tmp/my_fifo", 0777);
 8         if(res == 0)
 9         {
10                 printf("FIFO created\n");
11         }
12         exit(EXIT_SUCCESS);
13 }

使用FIFO

 1 #include<errno.h>
 2 #include<sys/stat.h>
 3 #include<fcntl.h>
 4 
 5 FIFO "/tmp/my_fifo"
 6 //本程序從一個FIFO讀數據,並把讀到的數據打印到標准輸出
 7 //如果讀到字符“Q”,則退出
 8 int main(int argc, char** argv)
 9 {
10         char buf_r[100];
11         int fd;
12         int nread;
13         if((mkfifo(FIFO, O_CREAT) < 0) && (errno != EEXIST))
14         {
15                 printf("不能創建FIFO\n");
16                 exit(1);
17         }
18 
19         printf("准備讀取數據\n");
20         fd = open(FIFO, O_RDONLY, 0);
21         if(fd == -1)
22         {
23                 perror("打開FIFO");
24                 exit(1);
25         }
26 
27         while(1)
28         {
29                 if((nread = read(fd, buf_r, 100)) == -1)
30                 {
31                         if(errno == EAGAIN) printf("沒有數據\n");
32                 }
33 
34                 //假設取到Q的時候退出
35                 if(buf_r[0]=='Q') break;
36 
37                 buf_r[nread]=0;
38                 printf("從FIFO讀取的數據為:%s\n", buf_r);
39                 sleep(1);
40         }
41 
42 }

 

 

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM