Linux進程間通訊-匿名管道

前面咱們講了進程間通訊的一種方式,共享內存。下面看一看另外一種機制,匿名管道。
1.什麼是管道
管道是一個進程的數據流到另外一個進程的通道,即一個進程的數據輸出做爲另外一個進程的數據輸入,管道起到了橋樑的做用。
好比,在shell中輸入命令:ls -l|grep string,ls和grep是兩個進程,"|"符號表示管道,意思是執行ls -l進程,並將輸出結果result_1,做爲grep string進程的輸入result_0,grep進程將result_0中存在字符串string的信息打印到屏幕。html

2.管道的使用
1)popen函數:啓用一個新進程,並能夠向它傳遞數據,或者經過它接受數據。shell

FILE *popen(const char *command,conse char *open_mode);

command:運行的程序名和參數
open_mode:有兩個值"r(只讀)","w(只寫)"
      "r":能夠獲取新進程的輸出
      "w":能夠向新進程發送數據
返回值:返回輸入輸出文件流指針數組

2)pclose函數:關閉輸入輸出文件流指針
若調用該函數時,新進程仍然在運行,則pclose將等待,直至新進程結束。
返回值:返回新進程的退出碼。函數

3.popen函數使用示例
下例循環讀取read_fp輸出文件流的內容,寫入write_fp的輸入文件流,直到輸出流內容讀完。spa

#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;

    //初始化緩衝區
    memset(buffer,'\0',sizeof(buffer));
    read_fp = popen("ls -l","r");
    write_fp = popen("grep rwxrwxr-x","w");
    if(read_fp && write_fp)
    {
        
        chars_read = fread(buffer,sizeof(char),BUFSIZ,read_fp);
        while(chars_read)
        {
            buffer[chars_read]='\0';
            //把數據寫入grep進程
            fwrite(buffer,sizeof(char),chars_read,write_fp);
            chars_read = fread(buffer,sizeof(char),BUFSIZ,read_fp);
        }
        //關閉文件流
        pclose(read_fp);
        pclose(write_fp);
        exit(EXIT_SUCCESS);
    }
    printf("%d\n",2);
    exit(EXIT_FAILURE);
}

輸出結果:指針

三、popen的原理及優缺點
當調用popen運行一個新進程時,它首先啓動shell,而後將command參數傳遞給它
優勢:可使用shell來分析命令字符串,啓動很是複雜的shell命令。
缺點:不只要啓動一個新進程,還要啓動一個shell,效率會比較低。code

4.pipe函數的使用htm

int pipe(int file_description[2]);

file_description[2]:表示管道的輸出輸入端,輸出端數據通過管道流到輸入端,函數執行完後, 會將這個數組賦值。
          file_description[1]表示管道輸出端文件描述符
          file_description[0]表示管道輸入端文件描述符
返回值:0成功,-1失敗blog

與popen不一樣的是,pipe函數是一個底層調用,不會啓動shell。
popen是使用文件流(FILE)工做的,pipe使用的是文件描述符,相應的數據要用底層的read和write來讀取和發送。進程

5.pipe函數使用示例
下例中,咱們在父進程中建立一個管道,而後調用fork建立一個子進程。
此時,父進程的file_description[1]輸出端,對應着子進程file_description[0]的輸入端。
數據經過管道由父進程傳到子進程。示例以下:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int main()
{
    int data_processed = 0;
    const char data[]="Hello pipe!";
    char buffer[BUFSIZ+1];
    pid_t pid;
    memset(buffer,'\0',sizeof(buffer));
    int filedes[2];
    if(pipe(filedes)==0)
    {
        //建立管道成功
        //fork子進程
        pid=fork();
        if(pid==-1)
        {
            fprintf(stderr,"Fork failure");
            exit(EXIT_FAILURE);
        }
        if(pid==0)
        {
            data_processed = read(filedes[0],buffer,BUFSIZ);
            printf("read %d bytes:%s\n",data_processed,buffer);
            exit(EXIT_SUCCESS);
        }
        else
        {
            data_processed = write(filedes[1],data,strlen(data));
            printf("wrote %d bytes:%s\n",data_processed,data);
            exit(EXIT_SUCCESS);
        }
    }
    exit(EXIT_FAILURE);
}

輸出結果:

6.管道用做標準輸入和輸出
咱們知道標準的輸入描述符爲0,輸出描述符爲1,
爲了使用已經定義好的標準程序,如od命令,從標準輸入讀入數據。
須要將管道的輸入端描述符置爲0,此時,咱們須要用到一個輔助函數dup

dup函數:建立一個描述符,複製原有描述符參數的結構到新建的描述符。

int dup(int file_descriptor);

新的描述符規則是,使用最小的可用值。

要想使管道的輸入描述符爲標準輸入描述符,咱們能夠先關閉文件描述符0,而後調用dup,
此時新建的描述符即爲最小可用值0,標準輸入描述符。

close(0);
dup(file_description[0]);

上例使用標準輸入描述符改造後的示例以下:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int main()
{
    int data_processed = 0;
    const char data[]="Hello pipe!";
    int filedes[2];
    pid_t pid;
    if(pipe(filedes)==0)
    {
        pid = fork();
        if(pid==-1)
        {
            fprintf("stderr","fork failure!\n");
            exit(EXIT_FAILURE);
        }
        if(pid==0)
        {
            close(0);
            dup(filedes[0]);
            close(filedes[0]);
            close(filedes[1]);
            execlp("od","od","-c",0);
            exit(EXIT_FAILURE);
        }
        else
        {
            close(filedes[0]);
            data_processed = write(filedes[1],data,strlen(data));
            close(filedes[1]);
            printf("wrote %d bytes:%s\n",data_processed,data);
        }
    }
}

輸出結果:

7.匿名管道須要注意的問題
1)當管道沒有關閉時,若沒有數據可讀,read調用會阻塞
2)當管道關閉時,read調用會返回0
3)匿名管道通訊,進程間必須是父子關係

相關文章
相關標籤/搜索