匿名管道應用的一個重大限制是它沒有名字,所以,只能用於具備親緣關係的進程間通訊,在有名管道(named pipe或FIFO)提出後,該限制獲得了克服。FIFO不一樣於管道之處在於它提供一個路徑名與之關聯,以FIFO的文件形式存在於文件系統中。這樣,即便與FIFO的建立進程不存在親緣關係的進程,只要能夠訪問該路徑,就可以彼此經過FIFO相互通訊linux
int mkfifo(const char * pathname, mode_t mode)ide
和普通文件建立同樣pathname爲文件名稱,mode爲權限spa
int close (int __fd);blog
1.當最後一個讀進程管道關閉時,寫進程不管是阻塞仍是非阻塞,都會將管道寫滿(若是能寫滿)並退出進程
2.當最後一個寫進程管道關閉時,向管道寫入一個結束標識,當讀進程從管道讀到這個結束標識時,若是是阻塞讀進程將結束阻塞返回讀入數據個數爲0.(對於未阻塞讀進程若是管道內沒有數據則返回-1,若是讀到結束標識則返回讀入數據個數爲0)ip
寫進程get
#include<unistd.h> #include<stdlib.h> #include<stdio.h> #include<string.h> #include<fcntl.h> #include<limits.h> #include<sys/types.h> #include<sys/stat.h> #include<errno.h> #define FIFO_NAME "/tmp/my_fifo" #define BUF_SIZE 80000 intmain(int argc, char *argv[]) { unlink(FIFO_NAME); int pipe_fd; int res; char buf[BUF_SIZE]; memset(buf, 3, BUF_SIZE); if (access(FIFO_NAME, F_OK) == -1) { res = mkfifo(FIFO_NAME, 0766); if (res != 0) { fprintf(stderr, "不能建立管道文件 %s\n", FIFO_NAME); exit(1); } } printf("進程PID %d 打開管道 O_WRONLY\n", getpid()); pipe_fd = open(FIFO_NAME, O_WRONLY); if (pipe_fd != -1) { res = write(pipe_fd, buf, sizeof(buf)); printf("寫入數據的大小是%d \n", res); close(pipe_fd); sleep(1000); } else exit(1); exit(1); }
讀進程string
#include<unistd.h> #include<stdlib.h> #include<stdio.h> #include<string.h> #include<fcntl.h> #include<limits.h> #include<sys/types.h> #include<sys/stat.h> #define FIFO_NAME "/tmp/my_fifo" #define BUF_SIZE 20 intmain(int argc, char *argv[]) { char buf[BUF_SIZE]; memset(buf, 0, BUF_SIZE); int pipe_fd; int res; int bytes_read = 0; printf("進程PID %d 打開管道 O_RDONLY\n", getpid()); pipe_fd = open(FIFO_NAME, O_RDONLY); if (pipe_fd != -1) { bytes_read = read(pipe_fd, buf, sizeof(buf)); printf("讀入數據的大小是%d \n", bytes_read); sleep(10); close(pipe_fd); } else exit(1); exit(1); }
控制檯信息it
讀進程:pip
進程PID 10930打開管道 O_RDONLY
讀入數據的大小是20
寫進程:
進程PID 10918打開管道 O_WRONLY
(10S後輸出…..)
寫入數據的大小是65536
分析:當讀進程執行到close(pipe_fd);時,寫進程一次性將數據寫滿緩衝區(65536)並退出。
寫進程
#define FIFO_NAME "/tmp/my_fifo" #define BUF_SIZE 80000 int main(int argc, char *argv[]) { unlink(FIFO_NAME); int pipe_fd; int res; char buf[BUF_SIZE]; memset(buf, 3, BUF_SIZE); if (access(FIFO_NAME, F_OK) == -1) { res = mkfifo(FIFO_NAME, 0766); if (res != 0) { fprintf(stderr, "不能建立管道文件 %s\n", FIFO_NAME); exit(1); } } printf("進程PID %d 打開管道 O_WRONLY\n", getpid()); pipe_fd = open(FIFO_NAME, O_WRONLY); if (pipe_fd != -1) { res = write(pipe_fd, buf, sizeof(buf)); printf("寫入數據的大小是%d \n", res); sleep(10); close(pipe_fd); } else exit(1); exit(1); }
讀進程
#define FIFO_NAME "/tmp/my_fifo" #define BUF_SIZE 4000 int main(int argc, char *argv[]) { char buf[BUF_SIZE]; memset(buf, 0, BUF_SIZE); int pipe_fd; int bytes_read = 0; printf("進程PID %d 打開管道 O_RDONLY\n", getpid()); pipe_fd = open(FIFO_NAME, O_RDONLY); if (pipe_fd != -1) { do { bytes_read = read(pipe_fd, buf, sizeof(buf)); printf("讀入數據的大小是%d \n", bytes_read); } while (bytes_read != 0); close(pipe_fd); } else exit(1); exit(1); }
控制檯輸出:
讀進程
進程PID 12240打開管道 O_RDONLY
讀入數據的大小是4000.
……
(10S後)
讀入數據的大小是0
寫進程
進程PID 12227打開管道 O_WRONLY
寫入數據的大小是80000
分析:
若是讀進程爲阻塞的,當寫進程關閉管道時,讀進程收到寫進程發來的結束符,讀進程結束阻塞(此時bytes_read =0)
若是讀進程爲非阻塞的,首先將全部數據讀取出來,而後在讀進程未收到寫進程發來的結束符時,因爲管道沒有數據讀進程不會阻塞且返回-1,由於此例WHILE退出條件是bytes_read =0,所以在未讀到結束符以前返回值一直是-1,直到讀取到結束符才返回0
對於設置了阻塞標誌的寫操做:
1.當要寫入的數據量不大於PIPE_BUF時,linux將保證寫入的原子性。若是此時管道空閒緩衝區不足以容納要寫入的字節數,則進入睡眠,直到當緩衝區中可以容納要寫入的字節數時,纔開始進行一次性寫操做。
2.當要寫入的數據量大於PIPE_BUF時,linux將再也不保證寫入的原子性。FIFO緩衝區一有空閒區域,寫進程就會試圖向管道寫入數據,寫操做在寫完全部請求寫的數據後返回。
對於沒有設置阻塞標誌的寫操做:
3.當要寫入的數據量大於PIPE_BUF時,linux將再也不保證寫入的原子性。在寫滿全部FIFO空閒緩衝區後,寫操做返回。
4.當要寫入的數據量不大於PIPE_BUF時,linux將保證寫入的原子性。若是當前FIFO空閒緩衝區可以容納請求寫入的字節數,寫完後成功返回;若是當前FIFO空閒緩衝區不可以容納請求寫入的字節數,則返回EAGAIN錯誤,提醒之後再寫
對於設置了阻塞標誌的寫操做:
1.若是有進程寫打開FIFO,且當前FIFO內沒有數據,將一直阻塞。
對於沒有設置阻塞標誌的寫操做:
2.若是有進程寫打開FIFO,且當前FIFO內沒有數據。則返回-1,當前errno值爲EAGAIN,提醒之後再試。
寫進程
#include<unistd.h> #include<stdlib.h> #include<stdio.h> #include<string.h> #include<fcntl.h> #include<limits.h> #include<sys/types.h> #include<sys/stat.h> #include <errno.h> #define FIFO_NAME "/tmp/my_fifo" #define BUF_SIZE 88888 int main(int argc,char *argv[]) { int pipe_fd; int res; char buf[BUF_SIZE]; memset(buf,3,BUF_SIZE); if(access(FIFO_NAME,F_OK)==-1) { res=mkfifo(FIFO_NAME,0766); if(res!=0) { fprintf(stderr,"不能建立管道文件 %s\n",FIFO_NAME); exit(1); } } printf("進程PID %d 打開管道 O_WRONLY\n",getpid()); pipe_fd=open(FIFO_NAME,O_WRONLY|O_TRUNC);//1 // pipe_fd=open(FIFO_NAME,O_WRONLY|O_TRUNC|O_NONBLOCK);//2 if(pipe_fd!=-1) { res=write(pipe_fd,buf,sizeof(buf)); printf("寫入數據的長度是%d \n",res); close(pipe_fd); } else exit(1); exit(1); }
讀進程
#include<unistd.h> #include<stdlib.h> #include<stdio.h> #include<string.h> #include<fcntl.h> #include<limits.h> #include<sys/types.h> #include<sys/stat.h> #define FIFO_NAME "/tmp/my_fifo" #define BUF_SIZE 4000 int main(int argc, char *argv[]) { int res; if(access(FIFO_NAME,F_OK)==-1) { res=mkfifo(FIFO_NAME,0766); if(res!=0) { fprintf(stderr,"不能建立管道文件 %s\n",FIFO_NAME); exit(1); } } char buf[BUF_SIZE]; memset(buf, 0, BUF_SIZE); int pipe_fd; int num=0; int bytes_read = 0; printf("進程PID %d 打開管道 O_RDONLY\n", getpid()); pipe_fd = open(FIFO_NAME, O_RDONLY);//3 //pipe_fd = open(FIFO_NAME, O_RDONLY|O_NONBLOCK);//4 if (pipe_fd != -1) { do { num++; bytes_read = read(pipe_fd, buf, sizeof(buf)); printf("第%d次讀入數據,數據的長度是%d \n",num, bytes_read); } while (bytes_read != 0); close(pipe_fd); } else exit(1); exit(1); }
上面兩段代碼分別是管道的讀端進程與寫端進程。其中有4個註釋行。分別表明
1. pipe_fd=open(FIFO_NAME,O_WRONLY|O_TRUNC);//1阻塞寫端
2. pipe_fd= open (FIFO_NAME,O_WRONLY|O_TRUNC|O_NONBLOCK);//2非阻塞寫端
3. pipe_fd =open(FIFO_NAME, O_RDONLY);//3阻塞讀端
4. pipe_fd =open(FIFO_NAME, O_RDONLY|O_NONBLOCK);//4非阻塞讀端
能夠分如下3種狀況分析:
說明:寫端與讀端不能同時都不阻塞
控制檯輸出以下:
讀端進程:
進程PID 5919打開管道 O_RDONLY
第1次讀入數據,數據的長度是-1
…………..
第5次讀入數據,數據的長度是4000
…………..
第26次讀入數據,數據的長度是4000
第27次讀入數據,數據的長度是888
第28次讀入數據,數據的長度是0
寫端進程:
進程PID 5906打開管道 O_WRONLY
寫入數據的長度是88888
分析:讀端知足讀端規則2,前面因爲寫進程還未開始寫入數據到管道所以返回-1
寫端知足寫端規則2
執行流程:先執行讀端程序,在執行寫端
控制檯輸出以下:
讀端進程:
進程PID 6046打開管道 O_RDONLY
第1次讀入數據,數據的長度是4000
…………
第16次讀入數據,數據的長度是4000
第17次讀入數據,數據的長度是1536
第18次讀入數據,數據的長度是0
寫端進程:
進程PID 6056打開管道 O_WRONLY
寫入數據的長度是65536
分析:讀端知足讀端規則1,讀進程在爲讀取到管道數據時一直處於等待阻塞狀態
寫端知足寫端規則3,寫端寫滿管道後推出,所以寫入數據長度是65535,而不是88888
控制檯輸出以下:
讀端進程:
進程PID 8386打開管道 O_RDONLY
第1次讀入數據,數據的長度是4000
…………
第22次讀入數據,數據的長度是4000
第23次讀入數據,數據的長度是888
第24次讀入數據,數據的長度是0
寫端進程:
進程PID 8373打開管道 O_WRONLY
寫入數據的長度是88888
分析:讀端知足讀端規則1,讀進程在爲讀取到管道數據時一直處於等待阻塞狀態
寫端知足寫端規則2