天天看點

linux作業系統之程序間通信 --管道

Linux環境下,程序位址空間互相獨立,每個程序各自有不同的使用者位址空間。任何一個程序的全局變量在另一個程序中都看不到,是以程序和程序之間不能互相通路,要交換資料必須通過核心,在核心中開辟一塊緩沖區,程序1把資料從使用者空間拷到核心緩沖區,程序2再從核心緩沖區把資料讀走,核心提供的這種機制稱為程序間通信(IPC,InterProcess Communication)。

在程序間完成資料傳遞需要借助作業系統提供特殊的方法,如:檔案、管道、信号、共享記憶體、消息隊列、套接字、命名管道等。随着計算機的蓬勃發展,一些方法由于自身設計缺陷被淘汰或者棄用。現今常用的程序間通信方式有:

① 管道 (使用最簡單)

② 信号 (開銷最小)

③ 共享映射區 (無血緣關系)

④ 本地套接字 (最穩定)

管道

未名管道(匿名管道)

管道是一種最基本的IPC機制,作用于有血緣關系的程序之間,完成資料傳遞。調用pipe系統函數即可建立一個管道。有如下特質:

1. 其本質是一個僞檔案(實為核心緩沖區)

linux檔案類型:- 檔案 d 目錄 l 符号連結

s 套接字 b塊裝置 c 字元裝置 p 管道 (這四種都是僞檔案)

  1. 由兩個檔案描述符引用,一個表示讀端,一個表示寫端。
  2. 規定資料從管道的寫端流入管道,從讀端流出。

    管道的原理: 管道實為核心使用環形隊列機制,借助核心緩沖區(4k)實作。

    管道的局限性:

    ① 資料自己讀不能自己寫。

    ② 資料一旦被讀走,便不在管道中存在,不可反複讀取。

    ③ 由于管道采用半雙工通信方式。是以,資料隻能在一個方向上流動。

    ④ 隻能在有公共祖先的程序間使用管道。(有血緣關系的程序)

    常見的通信方式有,單工通信、半雙工通信、全雙工通信。

pipe函數

建立管道

int pipe(int pipefd[2]); 成功:0;失敗:-1,設定errno

函數調用成功傳回r/w兩個檔案描述符。無需open,但需手動close。規定:fd[0] → r; fd[1] → w,就像0對應标準輸入,1對應标準輸出一樣。向管道檔案讀寫資料其實是在讀寫核心緩沖區。

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

int main()
{
    int fd[2];
    int ret =0;
    ret = pipe(fd);
    pid_t pid;
    if(ret == -1)
    {
            perror("pipe error.\n")
            exit(1);
    }
    pid = fork();
    if(pid == -1)
    {
            perror("fork error.\n");
            exit(1);
    }
    else if(pid ==0)
    {
            close(fd[1]);//子程序負責讀,是以關閉寫的描述符
            char buf[1024];
            ret = read(fd[0],buf,sizeof(buf));//從管道讀資料
            if(ret == 0)
            {
                    printf("end.\n");
            }
            write(STDOUT_FILENO,buf,ret);//寫到螢幕
    }
    else
    {
            close(fd[0]);//父程序負責寫,是以關閉讀的描述符
            char *str ="hello ,pipe.";
            write(fd[1],str,strlen(str));
    }
    return  0;
}   
           

FIFO

命名管道

FIFO常被稱為命名管道,以區分管道(pipe)。管道(pipe)隻能用于“有血緣關系”的程序間。但通過FIFO,不相關的程序也能交換資料。

FIFO是Linux基礎檔案類型中的一種。但,FIFO檔案在磁盤上沒有資料塊,僅僅用來辨別核心中一條通道。各程序可以打開這個檔案進行read/write,實際上是在讀寫核心通道,這樣就實作了程序間通信。

建立方式:

1. 指令:mkfifo 管道名

2. 庫函數:int mkfifo(const char *pathname, mode_t mode); 成功:0; 失敗:-1

一旦使用mkfifo建立了一個FIFO,就可以使用open打開它,常見的檔案I/O函數都可用于fifo。如:close、read、write、unlink等。

有名管道的打開規則:

有名管道比無名管道多了一個打開操作:open

FIFO的打開及讀寫規則:

一、對于FIFO,需要open去打開FIFO的讀端或是寫端的描述符。

1> 如果open的時候沒有指定O_NONBLOCK标志,且open的是讀端時

如果不存在此FIFO的已經打開的寫端時,open會一直阻塞到有FIFO的寫端打開;

如果已經存在此FIFO的打開的寫端時,open會直接成功傳回。

2> 如果open的時候沒有指定O_NONBLOCK标志,且open的是寫端時

如果不存在此FIFO的已經打開的讀端時,open會一直阻塞到有FIFO的讀端打開;

如果已經存在此FIFO的打開的讀端時,open會直接成功傳回。

二、從FIFO或者空管道讀寫

1> read時,讀端fd沒有指定O_NONBLOCK标志

如果存在此FIFO或管道的已經打開的寫端時,阻塞到FIFO或管道中有資料或者FIFO或管道的已經打開的寫端全部被關閉為止。

如果不存在此FIFO或管道的已經打開的寫端時,read傳回0;

2> write時, 同read差不多,就不詳述了。

繼續閱讀