IPC-管道(匿名管道)

管道(Pipe),也被叫做匿名管道,是UNIX系統IPC的最古老、最基本的機制,所以UNIX系統都提供此種通信機制。管道有兩個侷限性:

  • 最開始它是半雙工的(即數據只能在一個方向上流動)。現在,某些系統提供全雙工管道,但是爲了可移植性,我們應該假定系統不支持全雙工。
  • 管道只能在具有血緣關係的兩進程之間使用(兄弟進程、父子進程之類具有公共祖先的進程)。

管道是單向的、先進先出、無結構的字節流,它把一個進程的輸出和另一個進程的輸入連接在一起。

  • 在寫進程在管道尾端寫入數據,讀進程在管道的首端讀出數據。數據讀出後其他讀取進程都不能再讀到這些數據。
  • 當進程試圖讀取一個空管道時,在另一個寫入進程未寫入數據之前,進程將一直阻塞。管道已經滿時,進程再試圖將數據寫入管道,在別的讀取進程沒有讀取數據之前,寫入數據進程將阻塞。

管道的創建
管道基於文件描述符的通信方式,是通過調用pipe函數創建的。

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

調用pipe函數時在內核開闢一塊緩衝區(稱爲管道),它有一個讀端,一個寫端,然後通過參數傳出給用戶程序兩個文件描述符。fd[0]指向管道的讀端,fd[1]指向管道的寫端,就像標準輸入0,標準輸出1是一樣的。所以管道在用戶程序看起來就像是一個文件,對於它的讀寫也可以使用普通的read()和write()等函數。但是它不是普通的文件,並不屬於其他任何文件系統,只存在於內核的內存空間中。向它讀寫數據其實是在讀寫內核緩衝區。
返回值:調用失敗返回-1,成功返回0。
管道
管道創建步驟:
使用管道進行通信大致的步驟:
管道通信步驟

  1. 創建管道:父進程用pipe函數創建管道,得到兩個指向管道的文件描述符。
  2. 創建子進程:然後父進程fork出一個子進程,子進程繼承父進程的文件描述符,也得到兩個指向管道的文件描述符。
  3. 確定管道的傳輸方向(誰是讀端,誰是寫端):這裏父進程關閉讀端fd[0],子進程關閉寫端fd[1]。實現父進程向管道里寫數據,子進程從管道里面讀數據。這樣就實現了父子進程之間的通信。
  4. 通信:在寫進程中調用write()函數,在讀進程中調用read()函數
  5. 關閉管道:用close()關閉管道相關文件按。
    運用實例:
    在父進程中寫入”i am child!”然後在子進程中讀取,並且打印出來。
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main()
{
    pid_t id;
    int fd[2];
    int ret=pipe(fd);
    if(ret<0)
    {
        printf("pipe error!\n");
    }
    if(id=fork()<0)
    {
        printf("fork error!\n");
    }
    else if(id>0)//father
    {
        close(fd[0]);
        int i=0;
        char* mesg=NULL;
        while(i<100)
        {
            mesg="i am child!";
            write(fd[1],mesg,strlen(mesg)+1);
            sleep(1);
            i++;
        }
        close(fd[1]);
    }
    else//child
    {
        close(fd[1]);
        char mesg[100];
        int j=0;
        while(j<100)
        {
        ssize_t s=read(fd[0],mesg,sizeof(mesg));
        mesg[s-1]='\0';
        printf("%s\n",mesg);
        j++;
        }
        close(fd[0]);
    }
    return 0;
}

運行結果:
這裏寫圖片描述

使用管道還有一些限制:
上面說過兩個進程通過一個管道只能實現單項通信。比如上例,如果需要子進程寫,父進程讀就得另外開一個管道。
另外,需要注意有下面幾點情況:

  • 當讀一個寫端已經被關閉的管道時,在管道中所有數據都被讀取後,read返回0,表示文件結束。
  • 如果有指向管道寫端的⽂件描述符沒關閉(管道寫端的引⽤計數⼤於0),⽽持有管道寫端的 進程也沒有向管道中寫數據,這時有進程從管道讀端讀數據,那麼管道中剩餘的數據都被讀取後,再次read會阻塞,直到管道中有數據可讀了纔讀取數據並返回。
  • 如果有指向管道讀端的⽂件描述符沒關閉(管道讀端的引⽤計數⼤於0),⽽持有管道讀端的 進程也沒有從管道中讀數據,這時有進程向管道寫端寫數據,那麼在管道被寫滿時再 次write會阻塞,直到管道中有空位置了才寫⼊數據並返回。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章