Linux C:管道的实现原理,命名管道
目錄
一、管道
二、利用管道將寫進程和都進程連接起來
三、命名管道
一、管道
在Unix/Linux 中 命令行
? ?cmd1? |? cmd2? ? ? ? ? ? ? ? #例如? ? history | grep sqlplus?
其中 cmd1? 是? cmd2 是Linux中獨立的程序 , 而 “ | ” 符號在Linux 稱之為管道符。管道一端用來讀另一端用來寫。 把前一個進程的輸出結果作為后一個進程的輸入參數。例如
?history | grep sqlplus? 命令,前面一個是展示所有的歷史命令 ,而后面一個是對輸入中過濾出待關鍵字的sqlplus 的字符串。 兩個合起來就是? 展示所有的帶”sqlplus“的歷史命令。
在C程序中,方法 int? flag? =? pipe(int pd[2]);? 方法,輸入參數是一個至少2個元素的int數組。用來創建兩個文件描述符,這兩個文件描述符鏈接同一個臨時文件,?pd[0]用于從管道中讀數據, pd [1]用于從管道中寫數據。?如果創建成功flag 值為0 否則為-1。.
注意:在創建pipe 后,其中的一個文件描述符 pd[0] 沒有'w'權限,只有’r‘權限,而 pd[1] 沒有'r'權限,只有’w‘權限。
對文件描述符和IO重定向不了解的可以看看:
https://blog.csdn.net/superSmart_Dong/article/details/118531682
在下例代碼展示了用子進程和父進程利用管道讀寫數據的過程。由于子進程創建時會完全繼承父進程的文件描述符。意味著父進程中存在pd[2],那么子進程也有一樣的pd[2]。所以一個進程如果當作管道的寫進程,那么它的讀文件描述符就要先關閉,如果一個進程如果當作管道的讀進程,那么它的寫文件描述符就要關閉。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int pd[2] ,n,i; char line[256];int main(){pipe(pd); //pd[1]用于寫 , pd[0]用于讀printf("pd[ %d , %d ]",pd[0],pd[1]);if(fork()){//parent分支printf("parent %d close pd[0] \n",getpid());close(pd[0]);i =0;while( i++ <10){//假設父進程向管道寫入10次;n = write(pd[1],"I AM YOUR PAPA",16);printf("parent %d write %d byte to pipe\n",getpid(),n);}printf("parent %d exit\n",getpid());}else{//child 分支printf("child %d close pd[1] \n",getpid());close(pd[1]);while( 1){//管道讀入諾干;n = read(pd[0],line,128);if(n){printf(" child %d read %d byte from pipe\n :%s \n",getpid(),n,line);}else{exit(0);}}}}輸出結果可能不為一:其中一種輸出結果如圖。
二、利用管道將寫進程和都進程連接起來
在Linux 中當 sh? 獲取命令行? ?cmd1 | cmd2? ?時,會復刻出一個子進程sh。子進程sh會觀察命令行中是否有 ”|“ 管道符號,把命令行劃分為頭部和尾部
然后子進程執行一下代碼段:從而實現兩個進程通過管道和重定向IO實現對子進程的標準輸入的內容時父進程的標準輸出的內容。
int pd[2]; pipe(pd); int pid =fork(); if(pid){close(pd[0]); //父進程用于從管道中寫入數據,所以關閉讀fd(pd[0])close(1); dup(pd[1]); //拿pd[1]復制出一個最小未使用的fd = 1,讓標準輸出指向管道pd[1]所指的物理文件close(pd[1]); //關閉原來的pd[1]exec(cmd1); }else{close(pd[1]); //子進程用于從管道中讀入數據,所以關閉寫fd(pd[1])close(0); dup(pd[0]); //拿pd[0]復制出一個最小未使用的fd =0,讓標準輸入指向管道pd[0]所指的物理文件close(pd[0]); //關閉原來的pd[0]exec(cmd2); }三、命名管道
? 命名管道又叫做FIFO,在C語言中可以為管道命名。一個被賦予名字的管道。可以實現在兩個獨立進程或者兩個項目工程中進行數據交互。命名管道在文件系統中以特殊文件的形式存在,不是臨時文件,意味著,如果沒有把命名管道文件進行 rm 或者 unlink 刪除,則該管道會一致存在下去,除非儲存介質損壞。
在 sh 中:創建命名管道的命令為:
mknod? pipename??p
在C程序中,創建命名管道的系統調用為
int r =mknod("pipename",S_IFIFO,0)
可以利用在命名管道實現兩個獨立進程的數據交互
/*********寫管道進程*****************/#include <stdio.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> char *line = "name pipe message"; int main(){int fd ;mknod("mypipe",I_SFIFO,0);fd = open("mypipe",O_WRONLY);write(fd,line,strlen(line));close(fd); }在寫另外一個用于讀管道的C程序
/*********讀管道進程*****************/#include <stdio.h> #include <sys/stat.h> #include <fcntl.h>int main(){char buf[128];int fd = open("mypipe",O_RDONLY);read(fd,buf,128);printf("%s\n",buf);close(fd); }對這兩個C程序分別進行編譯。如果管道沒數據就讀內容的話,得到的輸入也是空的。就算進程生命結束,創建出來的命名管道依舊是存在的。
總結
以上是生活随笔為你收集整理的Linux C:管道的实现原理,命名管道的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux C:文件描述符、IO重定向、
- 下一篇: Linux C :线程操作和线程同步的多