概述 管道是?UNIX
系統(tǒng)?IPC
的最古老的形式,所有的UNIX
系統(tǒng)都提供此種通信。所謂的管道,也就是內(nèi)核里面的一串緩存,從管道的一段寫入的數(shù)據(jù),實(shí)際上是緩存在內(nèi)核中的,令一端讀取,也就是從內(nèi)核中讀取這段數(shù)據(jù)。對于管道傳輸?shù)臄?shù)據(jù)是無格式的流且大小受限。對于管道來說,也分為匿名管道和命名管道,其中命名管道也被叫做 FIFO,下面則分別闡述這兩種管道。匿名管道 默認(rèn)情況下,在?Shell
命令執(zhí)行過程中,任何一個(gè)命令都有一個(gè)標(biāo)準(zhǔn)輸入設(shè)備(鍵盤)、標(biāo)準(zhǔn)輸出設(shè)備(顯示器)和標(biāo)準(zhǔn)輸出設(shè)備(顯示器),使用管道"|"
可以將兩個(gè)命令連接起來,從而改變標(biāo)準(zhǔn)的輸入輸出方式,下面是在 Linux 端運(yùn)行命令行的一個(gè)截圖:image-20210704161819420 上述命令中的意思也就是,將ls
命令得到的結(jié)果作為?grep tags
命令的輸入。image-20210704162803903 連接輸入輸出的中間設(shè)備即為一個(gè)管道文件,綜上,也就是說使用管道可以將一個(gè)命令的輸出作為另一個(gè)命令的輸入(在運(yùn)行的時(shí)候,一個(gè)命令將創(chuàng)建一個(gè)進(jìn)程),而這種管道是臨時(shí)的,命令執(zhí)行完畢之后就會(huì)自動(dòng)消失,這類管道稱為無名管道 。匿名管道例子 匿名管道在使用前要先創(chuàng)建,其函數(shù)的聲明如下:extern ?int ?pipe ?(int ?__pipedes[2 ]) ;
此函數(shù)的參數(shù)是一個(gè)整型數(shù)組,如果執(zhí)行成功,pipe 將存儲(chǔ)兩個(gè)整型文件描述符于__pipedes[0]
和__pipedes[1]
中,他們分別指向管道的兩端。如果系統(tǒng)調(diào)用失敗,則返回 -1。讀無名管道,該函數(shù)的聲明如下:extern ?ssize_t?read ?(int ?__fd,?void ?*__buf,?size_t ?__nbytes) ;
第一個(gè)參數(shù)fd
為打開的文件描述符,buf
為讀出數(shù)據(jù)的存儲(chǔ)位置,nbytes
為讀取數(shù)據(jù)的大小,調(diào)用 read 函數(shù)將從 fd 指向的文件描述符指定的打開文件中宏讀?n
?字節(jié)到?buf
?指向的緩沖區(qū)內(nèi)。如果試圖向已經(jīng)填滿的管道寫入,系統(tǒng)會(huì)自動(dòng)阻塞。一個(gè)管道不能同時(shí)被兩個(gè)進(jìn)程打開。extern ?ssize_?t?write (int ?__fd,?__const?void ?*__buf,?size_t ?__n) ;
從?buf
指向的緩沖區(qū)中向管道中寫入nbytes
字節(jié),且每次寫入的內(nèi)容都附件在管道的末端。那要如何使用管道在兩個(gè)進(jìn)程之間通信呢,我們可以使用?fork()
創(chuàng)建子進(jìn)程,創(chuàng)建的子進(jìn)程會(huì)復(fù)制父進(jìn)程的文件描述符,這樣就做到了兩個(gè)進(jìn)程各有兩個(gè)fd[0]與fd[1]
,兩個(gè)進(jìn)程就可以通過各自的fd
寫入和讀取同一個(gè)管道文件實(shí)現(xiàn)進(jìn)程通信了,具體原理如下所示:image-20210704170602297 具體的例子如下所示:#include #include #include int ?main (int ?argc,?char ?*argv[]) { ????pid_t ?pid; ????int ?temp; ????int ?pipedes[2 ]; ????char ?s[14 ]?=?"test?message!" ; ????char ?d[14 ]; ????if ?(pipe(pipedes)?==?-1 )?//?創(chuàng)建管道 ????{ ????????perror("pipe" ); ????????exit (EXIT_FAILURE); ????} ????if ?(pid?==?fork()?==?-1 ) ????{ ????????perror("fork" ); ????????exit (EXIT_FAILURE); ????} ????else ?if ?(pid?==?0 )??????//?子進(jìn)程 ????{ ????????printf ("now,write?data?to?pipe\n" ); ????????if ?(write(pipedes[1 ],?s,?14 )?==?-1 )???//?寫數(shù)據(jù)到管道 ????????{ ????????????perror("write" ); ????????????exit (EXIT_FAILURE); ????????} ????????else ????????{ ????????????printf ("the?written?data?is:%s\n" ,s); ????????????exit (EXIT_SUCESS); ????????} ????} ????else ?if ?(pid?>?0 )?????//?父進(jìn)程 ????{ ????????slepp(2 ); ????????printf ("now,?read?from?pipe\n" ); ????????if ?((read(pipedes[0 ],?d,?14 ))?==?-1 ) ????????{ ????????????perror("read" ); ????????????exit (EXIT_FAILURE); ????????} ????????printf ("the?data?from?pipe?is:%s\n" ,d); ????} ????return ?0 ; }
代碼運(yùn)行的結(jié)果如下所示:image-20210704172243185 命名管道 命名管道又被稱之為是 FIFO ,未命名的管道只能在兩個(gè)相關(guān)的進(jìn)程之間使用,而且這兩個(gè)相關(guān)的進(jìn)程還要又一個(gè)共同創(chuàng)建了他們的祖先進(jìn)程,但是,通過 FIFO ,不相關(guān)的進(jìn)程也能交換數(shù)據(jù)。首先,介紹下是如何創(chuàng)建命名管道的:extern ?int ?mkfifo ?(__const?char ?*__path,?__mode_t ?__mode) ;
mkfifo
會(huì)根據(jù)參數(shù)建立特殊的有名管道文件,該文件必須不存在,而參數(shù)mode
為該文件的權(quán)限。下面是一個(gè)使用命名管道進(jìn)行進(jìn)程間通信的例子,例子分為兩個(gè)程序,分別是讀部分和寫部分,首先看先往管道寫數(shù)據(jù)的代碼,代碼如下所示:#include ?? #include ?? #include ?? #include ?? #include ?? #include ?? int ?main () ? {? ????int ?fd;? ????//?FIFO?file?path? ????char ?*?myfifo?=?"/tmp/myfifo" ;? ????//?Creating?the?named?file(FIFO)? ????//?mkfifo(,?)? ????mkfifo(myfifo,?0666 );? ????char ?arr1[80 ],?arr2[80 ];? ????while ?(1 )? ????{? ????????//?Open?FIFO?for?write?only? ????????fd?=?open(myfifo,?O_WRONLY);? ????????printf ("The?fd?is:%d\n" ,fd); ????????//?Take?an?input?arr2ing?from?user.? ????????//?80?is?maximum?length? ????????fgets(arr2,?80 ,?stdin );? ????????//?Write?the?input?arr2ing?on?FIFO? ????????//?and?close?it? ????????write(fd,?arr2,?strlen (arr2) 1 );? ????????close(fd);? ????????//?Open?FIFO?for?Read?only? ????????fd?=?open(myfifo,?O_RDONLY);? ????????//?Read?from?FIFO? ????????read(fd,?arr1,?sizeof (arr1));? ????????//?Print?the?read?message? ????????printf ("User2:?%s" ,?arr1);? ????????close(fd);? ????}? ????return ?0 ;? }
然后是先往管道讀數(shù)據(jù)的代碼,代碼如下所示:#include ?? #include ?? #include ?? #include ?? #include ?? #include ?? int ?main () ? {? ????int ?fd1;? ????//?FIFO?file?path? ????char ?*?myfifo?=?"/tmp/myfifo" ;? ????char ?str1[80 ],?str2[80 ];? ????while ?(1 )? ????{? ????????//?First?open?in?read?only?and?read? ????????fd1?=?open(myfifo,O_RDONLY);? ????????printf ("The?fd?is:%d\n" ,fd1); ????????read(fd1,?str1,?80 );? ????????//?Print?the?read?string?and?close? ????????printf ("User1:?%s" ,?str1);? ????????close(fd1);? ????????//?Now?open?in?write?mode?and?write? ????????//?string?taken?from?user.? ????????fd1?=?open(myfifo,O_WRONLY);? ????????fgets(str2,?80 ,?stdin );? ????????write(fd1,?str2,?strlen (str2) 1 );? ????????close(fd1);? ????}? ????return ?0 ;? }?
下面是代碼運(yùn)行的一個(gè)結(jié)果:image-20210706132916572 說明一下,就是說當(dāng)運(yùn)行?write
程序的時(shí)候,會(huì)創(chuàng)建fifo
文件,命名管道,然后,在?write
文件中就執(zhí)行open
操作,但是,這里存在的一個(gè)問題就是,因?yàn)樵谶\(yùn)行?write
程序的時(shí)候,沒有進(jìn)程打開讀端,也就阻塞了?open
函數(shù)的運(yùn)行,只有運(yùn)行read
操作,以讀的方式讀取管道的數(shù)據(jù),這樣才能使得write
中的open
函數(shù)繼續(xù)執(zhí)行。綜上,也就是命名管道在進(jìn)程中通信的一個(gè)例子。小結(jié) 上述就是本次進(jìn)程通信中關(guān)于管道的相關(guān)內(nèi)容,其中就包括匿名管道以及命名管道,他們之間存在著差別嗎,也各有各的應(yīng)用,本次的分享就到這里啦~你點(diǎn)的每個(gè)好看,我都認(rèn)真當(dāng)成了喜歡
本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。