linux系統編程之管道(一):匿名管道(pipe)

一,什麼是管道

管道是Linux支持的最初Unix IPC形式之一,具備如下特色: html

  • 管道是半雙工的,數據只能向一個方向流動;須要雙方通訊時,須要創建起兩個管道;
  • 只能用於父子進程或者兄弟進程之間(具備親緣關係的進程);
  • 單獨構成一種獨立的文件系統:管道對於管道兩端的進程而言,就是一個文件,但它不是普通的文件,它不屬於某種文件系統,而是自立門戶,單獨構成一種文件系統,而且只存在與內存中。
  • 數據的讀出和寫入:一個進程向管道中寫的內容被管道另外一端的進程讀出。寫入的內容每次都添加在管道緩衝區的末尾,而且每次都是從緩衝區的頭部讀出數據。

管道的實現機制:linux

    管道是由內核管理的一個緩衝區,至關於咱們放入內存中的一個紙條。管道的一端鏈接一個進程的輸出。這個進程會向管道中放入信息。管道的另外一端鏈接一個進程的輸入,這個進程取出被放入管道的信息。一個緩衝區不須要很大,它被設計成爲環形的數據結構,以便管道能夠被循環利用。當管道中沒有信息的話,從管道中讀取的進程會等待,直到另外一端的進程放入信息。當管道被放滿信息的時候,嘗試放入信息的進程會等待,直到另外一端的進程取出信息。當兩個進程都終結的時候,管道也自動消失。數組

二,管道的建立(pipe)

包含頭文件<unistd.h> 數據結構

功能:建立一無名管道 函數

原型: spa

int pipe(int fd[2]); 設計

參數: 3d

fd:文件描述符數組,其中fd[0]表示讀端, fd[1]表示寫端 code

返回值:成功返回0,失敗返回錯誤代碼 htm

man幫助說明:

DESCRIPTION       

       pipe() creates a pipe, a unidirectional data channel that can be used
       for interprocess communication.  The array pipefd is used to return
       two file descriptors referring to the ends of the pipe.  pipefd[0]
       refers to the read end of the pipe.  pipefd[1] refers to the write
       end of the pipe.  Data written to the write end of the pipe is
       buffered by the kernel until it is read from the read end of the
       pipe.  For further details, see pipe(7).
 
該函數建立的管道的兩端處於一個進程中間,在實際應 用中沒有太大意義,所以,一個進程在由pipe()建立管道後,通常再fork一個子進程,而後經過管道實現父子進程間的通訊(所以也不難推出,只要兩個 進程中存在親緣關係,這裏的親緣關係指的是具備共同的祖先,均可以採用管道方式來進行通訊)。父子進程間具備相同的文件描述符,且指向同一個管道pipe,其餘沒有關係的進程不能得到pipe()產生的兩個文件描述符,也就不能利用同一個管道進行通訊。
建立管道後示意圖:
QQ截圖20130715212929
 
三,利用管道進行父子進程間數據傳輸
示例一:子進程向管道中寫數據,父進程從管道中讀出數據
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> 

int main(void)
{
    int fds[2];
    if(pipe(fds) == -1){
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if(pid == -1){
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if(pid == 0){
        close(fds[0]);//子進程關閉讀端
        write(fds[1],"hello",5);
        exit(EXIT_SUCCESS);
    }

    close(fds[1]);//父進程關閉寫端
    char buf[10] = {0};
    read(fds[0],buf,10);
    printf("receive datas = %s\n",buf);
    return 0;
}

結果:

QQ截圖20130715214531

示例二:利用管道實現ls |wc –w功能

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h> 

int main(void)
{
    int fds[2];
    if(pipe(fds) == -1){
        perror("pipe error");
        exit(EXIT_FAILURE);
    }
    pid_t pid;
    pid = fork();
    if(pid == -1){
        perror("fork error");
        exit(EXIT_FAILURE);
    }
    if(pid == 0){
        
        dup2(fds[1],STDOUT_FILENO);//複製文件描述符且指定新複製的fd爲標準輸出
        close(fds[0]);//子進程關閉讀端
        close(fds[1]);
        execlp("ls","ls",NULL);
        fprintf(stderr,"exec error\n");
        exit(EXIT_FAILURE);
    }

    dup2(fds[0],STDIN_FILENO);
    close(fds[1]);//父進程關閉寫端
    close(fds[0]);
    execlp("wc","wc","-w",NULL);
    fprintf(stderr, "error execute wc\n");
    exit(EXIT_FAILURE);
}

結果:

QQ截圖20130715215608

相關文章
相關標籤/搜索