五月综合激情婷婷六月,日韩欧美国产一区不卡,他扒开我内裤强吻我下面视频 ,无套内射无矿码免费看黄,天天躁,日日躁,狠狠躁

新聞動(dòng)態(tài)

Linux通過(guò)匿名管道進(jìn)行進(jìn)程間通信

發(fā)布日期:2022-04-14 19:13 | 文章來(lái)源:站長(zhǎng)之家

本文研究的主要是Linux通過(guò)匿名管道進(jìn)行進(jìn)程間通信的相關(guān)內(nèi)容,具體介紹如下。

在前面,介紹了一種進(jìn)程間的通信方式:使用信號(hào),我們創(chuàng)建通知事件,并通過(guò)它引起響應(yīng),但傳遞的信息只是一個(gè)信號(hào)值。這里將介紹另一種進(jìn)程間通信的方式——匿名管道,通過(guò)它進(jìn)程間可以交換更多有用的數(shù)據(jù)。

一、什么是管道

如果你使用過(guò)Linux的命令,那么對(duì)于管道這個(gè)名詞你一定不會(huì)感覺(jué)到陌生,因?yàn)槲覀兺ǔMㄟ^(guò)符號(hào)“|"來(lái)使用管道,但是管理的真正定義是什么呢?管道是一個(gè)進(jìn)程連接數(shù)據(jù)流到另一個(gè)進(jìn)程的通道,它通常是用作把一個(gè)進(jìn)程的輸出通過(guò)管道連接到另一個(gè)進(jìn)程的輸入。

舉個(gè)例子,在shell中輸入命令:ls -l | grep string,我們知道ls命令(其實(shí)也是一個(gè)進(jìn)程)會(huì)把當(dāng)前目錄中的文件都列出來(lái),但是它不會(huì)直接輸出,而是把本來(lái)要輸出到屏幕上的數(shù)據(jù)通過(guò)管道輸出到grep這個(gè)進(jìn)程中,作為grep這個(gè)進(jìn)程的輸入,然后這個(gè)進(jìn)程對(duì)輸入的信息進(jìn)行篩選,把存在string的信息的字符串(以行為單位)打印在屏幕上。

二、使用popen函數(shù)

1、popen函數(shù)和pclose函數(shù)介紹

有靜就有動(dòng),有開(kāi)就有關(guān),與此相同,與popen函數(shù)相對(duì)應(yīng)的函數(shù)是pclose函數(shù),它們的原型如下:

#include <stdio.h> 
FILE* popen (const char *command, const char *open_mode); 
int pclose(FILE *stream_to_close); 

poen函數(shù)允許一個(gè)程序?qū)⒘硪粋€(gè)程序作為新進(jìn)程來(lái)啟動(dòng),并可以傳遞數(shù)據(jù)給它或者通過(guò)它接收數(shù)據(jù)。command是要運(yùn)行的程序名和相應(yīng)的參數(shù)。open_mode只能是"r(只讀)"和"w(只寫)"的其中之一。注意,popen函數(shù)的返回值是一個(gè)FILE類型的指針,而Linux把一切都視為文件,也就是說(shuō)我們可以使用stdio I/O庫(kù)中的文件處理函數(shù)來(lái)對(duì)其進(jìn)行操作。

如果open_mode是"r",主調(diào)用程序就可以使用被調(diào)用程序的輸出,通過(guò)函數(shù)返回的FILE指針,就可以能過(guò)stdio函數(shù)(如fread)來(lái)讀取程序的輸出;如果open_mode是"w",主調(diào)用程序就可以向被調(diào)用程序發(fā)送數(shù)據(jù),即通過(guò)stdio函數(shù)(如fwrite)向被調(diào)用程序?qū)憯?shù)據(jù),而被調(diào)用程序就可以在自己的標(biāo)準(zhǔn)輸入中讀取這些數(shù)據(jù)。

pclose函數(shù)用于關(guān)閉由popen創(chuàng)建出的關(guān)聯(lián)文件流。pclose只在popen啟動(dòng)的進(jìn)程結(jié)束后才返回,如果調(diào)用pclose時(shí)被調(diào)用進(jìn)程仍在運(yùn)行,pclose調(diào)用將等待該進(jìn)程結(jié)束。它返回關(guān)閉的文件流所在進(jìn)程的退出碼。

2、例子

很多時(shí)候,我們根本就不知道輸出數(shù)據(jù)的長(zhǎng)度,為了避免定義一個(gè)非常大的數(shù)組作為緩沖區(qū),我們可以以塊的方式來(lái)發(fā)送數(shù)據(jù),一次讀取一個(gè)塊的數(shù)據(jù)并發(fā)送一個(gè)塊的數(shù)據(jù),直到把所有的數(shù)據(jù)都發(fā)送完。下面的例子就是采用這種方式的數(shù)據(jù)讀取和發(fā)送方式。源文件名為popen.c,代碼如下:

#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
 
int main() 
{ 
  FILE *read_fp = NULL; 
  FILE *write_fp = NULL; 
  char buffer[BUFSIZ + 1]; 
  int chars_read = 0; 
   
  //初始化緩沖區(qū) 
  memset(buffer, '\0', sizeof(buffer)); 
  //打開(kāi)ls和grep進(jìn)程 
  read_fp = popen("ls -l", "r"); 
  write_fp = popen("grep rwxrwxr-x", "w"); 
  //兩個(gè)進(jìn)程都打開(kāi)成功 
  if(read_fp && write_fp) 
  { 
    //讀取一個(gè)數(shù)據(jù)塊 
    chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp); 
    while(chars_read > 0) 
    { 
      buffer[chars_read] = '\0'; 
      //把數(shù)據(jù)寫入grep進(jìn)程 
      fwrite(buffer, sizeof(char), chars_read, write_fp); 
      //還有數(shù)據(jù)可讀,循環(huán)讀取數(shù)據(jù),直到讀完所有數(shù)據(jù) 
      chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp); 
    } 
    //關(guān)閉文件流 
    pclose(read_fp); 
    pclose(write_fp); 
    exit(EXIT_SUCCESS); 
  } 
  exit(EXIT_FAILURE); 
} 

運(yùn)行結(jié)果如下:

從運(yùn)行結(jié)果來(lái)看,達(dá)到了信息篩選的目的。程序在進(jìn)程ls中讀取數(shù)據(jù),再把數(shù)據(jù)發(fā)送到進(jìn)程grep中進(jìn)行篩選處理,相當(dāng)于在shell中直接輸入命令:ls -l | grep rwxrwxr-x。

3、popen的實(shí)現(xiàn)方式及優(yōu)缺點(diǎn)

當(dāng)請(qǐng)求popen調(diào)用運(yùn)行一個(gè)程序時(shí),它首先啟動(dòng)shell,即系統(tǒng)中的sh命令,然后將command字符串作為一個(gè)參數(shù)傳遞給它。

這樣就帶來(lái)了一個(gè)優(yōu)點(diǎn)和一個(gè)缺點(diǎn)。優(yōu)點(diǎn)是:在Linux中所有的參數(shù)擴(kuò)展都是由shell來(lái)完成的。所以在啟動(dòng)程序(command中的命令程序)之前先啟動(dòng)shell來(lái)分析命令字符串,也就可以使各種shell擴(kuò)展(如通配符)在程序啟動(dòng)之前就全部完成,這樣我們就可以通過(guò)popen啟動(dòng)非常復(fù)雜的shell命令。

而它的缺點(diǎn)就是:對(duì)于每個(gè)popen調(diào)用,不僅要啟動(dòng)一個(gè)被請(qǐng)求的程序,還要啟動(dòng)一個(gè)shell,即每一個(gè)popen調(diào)用將啟動(dòng)兩個(gè)進(jìn)程,從效率和資源的角度看,popen函數(shù)的調(diào)用比正常方式要慢一些。

三、pipe調(diào)用

如果說(shuō)popen是一個(gè)高級(jí)的函數(shù),pipe則是一個(gè)底層的調(diào)用。與popen函數(shù)不同的是,它在兩個(gè)進(jìn)程之間傳遞數(shù)據(jù)不需要啟動(dòng)一個(gè)shell來(lái)解釋請(qǐng)求命令,同時(shí)它還提供對(duì)讀寫數(shù)據(jù)的更多的控制。

pipe函數(shù)的原型如下:

#include <unistd.h> 
int pipe(int file_descriptor[2]); 

我們可以看到pipe函數(shù)的定義非常特別,該函數(shù)在數(shù)組中墻上兩個(gè)新的文件描述符后返回0,如果返回返回-1,并設(shè)置errno來(lái)說(shuō)明失敗原因。

數(shù)組中的兩個(gè)文件描述符以一種特殊的方式連接起來(lái),數(shù)據(jù)基于先進(jìn)先出的原則,寫到file_descriptor[1]的所有數(shù)據(jù)都可以從file_descriptor[0]讀回來(lái)。由于數(shù)據(jù)基于先進(jìn)先出的原則,所以讀取的數(shù)據(jù)和寫入的數(shù)據(jù)是一致的。

特別提醒:

1、從函數(shù)的原型我們可以看到,它跟popen函數(shù)的一個(gè)重大區(qū)別是,popen函數(shù)是基于文件流(FILE)工作的,而pipe是基于文件描述符工作的,所以在使用pipe后,數(shù)據(jù)必須要用底層的read和write調(diào)用來(lái)讀取和發(fā)送。

2、不要用file_descriptor[0]寫數(shù)據(jù),也不要用file_descriptor[1]讀數(shù)據(jù),其行為未定義的,但在有些系統(tǒng)上可能會(huì)返回-1表示調(diào)用失敗。數(shù)據(jù)只能從file_descriptor[0]中讀取,數(shù)據(jù)也只能寫入到file_descriptor[1],不能倒過(guò)來(lái)。

例子:

首先,我們?cè)谠鹊倪M(jìn)程中創(chuàng)建一個(gè)管道,然后再調(diào)用fork創(chuàng)建一個(gè)新的進(jìn)程,最后通過(guò)管道在兩個(gè)進(jìn)程之間傳遞數(shù)據(jù)。源文件名為pipe.c,代碼如下:

#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
 
int main() 
{ 
  int data_processed = 0; 
  int filedes[2]; 
  const char data[] = "Hello pipe!"; 
  char buffer[BUFSIZ + 1]; 
  pid_t pid; 
  //清空緩沖區(qū) 
  memset(buffer, '\0', sizeof(buffer)); 
 
  if(pipe(filedes) == 0) 
  { 
    //創(chuàng)建管道成功 
    //通過(guò)調(diào)用fork創(chuàng)建子進(jìn)程 
    pid = fork(); 
    if(pid == -1) 
    { 
      fprintf(stderr, "Fork failure"); 
      exit(EXIT_FAILURE); 
    } 
    if(pid == 0) 
    { 
      //子進(jìn)程中 
      //讀取數(shù)據(jù) 
      data_processed = read(filedes[0], buffer, BUFSIZ); 
      printf("Read %d bytes: %s\n", data_processed, buffer); 
      exit(EXIT_SUCCESS); 
    } 
    else 
    { 
      //父進(jìn)程中 
      //寫數(shù)據(jù) 
      data_processed = write(filedes[1], data, strlen(data)); 
      printf("Wrote %d bytes: %s\n", data_processed, data); 
      //休眠2秒,主要是為了等子進(jìn)程先結(jié)束,這樣做也只是純粹為了輸出好看而已 
      //父進(jìn)程其實(shí)沒(méi)有必要等等子進(jìn)程結(jié)束 
      sleep(2); 
      exit(EXIT_SUCCESS); 
    } 
  } 
  exit(EXIT_FAILURE); 
} 

運(yùn)行結(jié)果為:

可見(jiàn),子進(jìn)程讀取了父進(jìn)程寫到filedes[1]中的數(shù)據(jù),如果在父進(jìn)程中沒(méi)有sleep語(yǔ)句,父進(jìn)程可能在子進(jìn)程結(jié)束前結(jié)束,這樣你可能將看到兩個(gè)輸入之間有一個(gè)命令提示符分隔。

四、把管道用作標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出

下面來(lái)介紹一種用管道來(lái)連接兩個(gè)進(jìn)程的更簡(jiǎn)潔方法,我們可以把文件描述符設(shè)置為一個(gè)已知值,一般是標(biāo)準(zhǔn)輸入0或標(biāo)準(zhǔn)輸出1。這樣做最大的好處是可以調(diào)用標(biāo)準(zhǔn)程序,即那些不需要以文件描述符為參數(shù)的程序。

為了完成這個(gè)工作,我們還需要兩個(gè)函數(shù)的輔助,它們分別是dup函數(shù)或dup2函數(shù),它們的原型如下

#include <unistd.h> 
int dup(int file_descriptor); 
int dup2(int file_descriptor_one, int file_descriptor_two); 

dup調(diào)用創(chuàng)建一個(gè)新的文件描述符與作為它的參數(shù)的那個(gè)已有文件描述符指向同一個(gè)文件或管道。對(duì)于dup函數(shù)而言,新的文件描述總是取最小的可用值。而dup2所創(chuàng)建的新文件描述符或者與int file_descriptor_two相同,或者是第一個(gè)大于該參數(shù)的可用值。所以當(dāng)我們首先關(guān)閉文件描述符0后調(diào)用dup,那么新的文件描述符將是數(shù)字0.

例子

在下面的例子中,首先打開(kāi)管道,然后fork一個(gè)子進(jìn)程,然后在子進(jìn)程中,使標(biāo)準(zhǔn)輸入指向讀管道,然后關(guān)閉子進(jìn)程中的讀管道和寫管道,只留下標(biāo)準(zhǔn)輸入,最后調(diào)用execlp函數(shù)來(lái)啟動(dòng)一個(gè)新的進(jìn)程od,但是od并不知道它的數(shù)據(jù)來(lái)源是管道還是終端。父進(jìn)程則相對(duì)簡(jiǎn)單,它首先關(guān)閉讀管道,然后在寫管道中寫入數(shù)據(jù),再關(guān)閉寫管道就完成了它的任務(wù)。源文件為pipe2.c,代碼如下:

#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
 
int main() 
{ 
  int data_processed = 0; 
  int pipes[2]; 
  const char data[] = "123"; 
  pid_t pid; 
 
  if(pipe(pipes) == 0) 
  { 
    pid = fork(); 
    if(pid == -1) 
    { 
      fprintf(stderr, "Fork failure!\n"); 
      exit(EXIT_FAILURE); 
    } 
    if(pid == 0) 
    { 
      //子進(jìn)程中 
      //使標(biāo)準(zhǔn)輸入指向fildes[0] 
      close(0); 
      dup(pipes[0]); 
      //關(guān)閉pipes[0]和pipes[1],只剩下標(biāo)準(zhǔn)輸入 
      close(pipes[0]); 
      close(pipes[1]); 
      //啟動(dòng)新進(jìn)程od 
      execlp("od", "od", "-c", 0); 
      exit(EXIT_FAILURE); 
    } 
    else 
    { 
      //關(guān)閉pipes[0],因?yàn)楦高M(jìn)程不用讀取數(shù)據(jù) 
      close(pipes[0]); 
      data_processed = write(pipes[1], data, strlen(data)); 
      //寫完數(shù)據(jù)后,關(guān)閉pipes[1] 
      close(pipes[1]); 
      printf("%d - Wrote %d bytes\n", getpid(), data_processed); 
    } 
  } 
  exit(EXIT_SUCCESS); 
} 

運(yùn)行結(jié)果為:

從運(yùn)行結(jié)果中可以看出od進(jìn)程正確地完成了它的任務(wù),與在shell中直接輸入od -c和123的效果一樣。

五、關(guān)于管道關(guān)閉后的讀操作的討論

現(xiàn)在有這樣一個(gè)問(wèn)題,假如父進(jìn)程向管道file_pipe[1]寫數(shù)據(jù),而子進(jìn)程在管道file_pipe[0]中讀取數(shù)據(jù),當(dāng)父進(jìn)程沒(méi)有向file_pipe[1]寫數(shù)據(jù)時(shí),子進(jìn)程則沒(méi)有數(shù)據(jù)可讀,則子進(jìn)程會(huì)發(fā)生什么呢?再者父進(jìn)程把file_pipe[1]關(guān)閉了,子進(jìn)程又會(huì)有什么反應(yīng)呢?

當(dāng)寫數(shù)據(jù)的管道沒(méi)有關(guān)閉,而又沒(méi)有數(shù)據(jù)可讀時(shí),read調(diào)用通常會(huì)阻塞,但是當(dāng)寫數(shù)據(jù)的管道關(guān)閉時(shí),read調(diào)用將會(huì)返回0而不是阻塞。注意,這與讀取一個(gè)無(wú)效的文件描述符不同,read一個(gè)無(wú)效的文件描述符返回-1。

六、匿名管道的缺陷

看了這么多相信大家也知道它的一個(gè)缺點(diǎn),就是通信的進(jìn)程,它們的關(guān)系一定是父子進(jìn)程的關(guān)系,這就使得它的使用受到了一點(diǎn)的限制,但是我們可以使用命名管道來(lái)解決這個(gè)問(wèn)題。命名管道將在下一篇文章:Linux進(jìn)程間通信——使用命名管道中介紹。

總結(jié)

以上就是本文關(guān)于Linux通過(guò)匿名管道進(jìn)行進(jìn)程間通信的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!

版權(quán)聲明:本站文章來(lái)源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請(qǐng)保持原文完整并注明來(lái)源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非maisonbaluchon.cn所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來(lái)源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來(lái),僅供學(xué)習(xí)參考,不代表本站立場(chǎng),如有內(nèi)容涉嫌侵權(quán),請(qǐng)聯(lián)系alex-e#qq.com處理。

相關(guān)文章

實(shí)時(shí)開(kāi)通

自選配置、實(shí)時(shí)開(kāi)通

免備案

全球線路精選!

全天候客戶服務(wù)

7x24全年不間斷在線

專屬顧問(wèn)服務(wù)

1對(duì)1客戶咨詢顧問(wèn)

在線
客服

在線客服:7*24小時(shí)在線

客服
熱線

400-630-3752
7*24小時(shí)客服服務(wù)熱線

關(guān)注
微信

關(guān)注官方微信
頂部