1. 程式人生 > >Linux程序通訊之管道和FIFO

Linux程序通訊之管道和FIFO

Linux程序間的通訊可以簡稱為IPCInterprocess Communication),前面說過的 Linux的同步工具也是屬於IPC的一部分,這裡我想說的是通常意義的程序間的實際資料通。

1管道

管道是最早的UNIX IPC,所有的UNIX系統都支援這個IPC通訊機制。我們最常見到使用它的位置就是shell中使用的管道命令。管道IPC有兩個特性:

  • 管道僅提供半雙工的資料通訊,即只支援單向的資料流
  • 管道只能在有親緣關係的程序間使用。這是由於管道沒有名字的原因,所以不能跨程序的地址空間進行使用。這裡這句話不是絕對的因為從技術上可以在程序間傳遞管道的描述符,所以是可以通過管道實現無親緣程序間的通訊的。但儘管如此,管道還是通常用於具有共同祖先的程序間的通訊。

管道的介面定義如下:

#include <unistd.h>
int pipe(int filedes[2]);
                       //成功返回0,失敗返回-1

pipe函式用來建立一個管道,fd是傳出引數,用於儲存返回的兩個檔案描述符,該檔案描述符用於標識管道的兩端,fd[0]只能由於讀,fd[1]只能用於寫。

那麼如果我們往fd[0]端寫資料會是什麼樣的結果呢?下面是測試程式碼:

#include <iostream>
#include <cstring>

#include <unistd.h>
#include <errno.h>

using namespace std;

int main()
{
    int fd[2];

    if (pipe(fd) < 0)
    {
        cout<<"create pipe failed..."<<endl;
        return -1;
    }

    char *temp = "yuki";

    if (write(fd[0], temp, strlen(temp) + 1) < 0)
    {
        cout<<"write pipe failed:"<<strerror(errno)<<endl;
    }

    return 0;
}
程式碼的執行結果如下:
 write pipe failed:Bad file descriptor

從這個結果可以看出,核心對於管道的fd[0]描述符開啟的方式是以只讀方式開啟的,那麼同理fd[1]是以只寫方式開啟的,所以管道只能保證單向的資料通訊。

下圖1顯示的是一個程序內的管道的模樣:


1單個程序內管道的模樣

從上圖我們可以看到位於核心中的管道,程序通過兩個檔案描述符進行資料的傳輸,當然單個程序內的管道是沒有必要的,上面只是為了更形象的表明管道的工作方式,一般管道的使用方式都是:父程序建立一個管道,然後fork產生一個子程序,由於子程序繼承父程序開啟的檔案描述符,所以父子程序可以通過管道程序通訊。這種使用方式如下圖

2所示:


2父子程序間的管道

如上圖所示,當父程序通過fork建立子程序後,父子程序都擁有對管道操作的檔案描述符,此時父子程序關閉對應的讀寫端,使父子程序間形成單向的管道。關閉哪個端要根據具體的資料流向決定。

1.1父子程序間的單向通訊

上面說了父程序通過fork建立子程序後,父子程序間可以通過管道通訊,資料流的方向根據具體的應用決定。我們都知道在shell中,管道的資料流向都是從父程序流向子程序,即父程序關閉讀端,子程序關閉寫端。如下圖3所示:


父子程序間的單向管道

上圖的測試程式碼如下:

#include <iostream>

#include <unistd.h>

using namespace std;

int main()
{
    int fd[2];

    if (pipe(fd) < 0)
    {
        cout<<"create pipe failed..."<<endl;
        return -1;
    }

    char buf[256];

    if (fork() == 0)
    {
        close(fd[1]);

        read(fd[0], buf, sizeof(buf));
        cout<<"receive message from pipe:"<<buf<<endl;

        exit(0);
    }

    close(fd[0]);

    char *temp = "I have liked yuki...";
    write(fd[1], temp, strlen(temp) + 1);

    return 0;
}

程式碼的執行結果如下:

receive message from pipe:I have liked yuki...

其中程式碼流程是,子程序等待父程序通過管道傳送過來的資料,然後輸出接收到的資料,程式碼中的read會阻塞到管道中有資料為止,具體管道的readwrite的規則將會在後面介紹。

1.2父子程序間的雙向通訊

由上我們知道,一個管道只能支援親緣程序間的單向通訊即半雙工通訊。如果要想通過管道來支援雙向通訊呢,那這裡就需要建立兩個管道,fd1fd2;父程序中關閉fd1[0]fd2[1],子程序中關閉fd1[1]fd2[0]。這種通訊模式如下圖所示:


圖 父子程序間的雙向通訊

下面是雙向通訊的測試程式碼:

#include <iostream>

#include <unistd.h>

using namespace std;

int main()
{
    int fd1[2], fd2[2];

    if (pipe(fd1) < 0 || pipe(fd2) < 0)
    {
        cout<<"create pipe failed..."<<endl;
        return -1;
    }

    char buf[256];
    char *temp = "I have liked yuki...";

    if (fork() == 0)
    {
        close(fd1[1]);
        close(fd2[0]);

        read(fd1[0], buf, sizeof(buf));
        cout<<"child:receive message from pipe 1:"<<buf<<endl;

        write(fd2[1], temp, strlen(temp) + 1);
        exit(0);
    }

    close(fd1[0]);
    close(fd2[1]);

    write(fd1[1], temp, strlen(temp) + 1);
    read(fd2[0], buf, sizeof(buf));
    cout<<"parent:receive message from pipe 2:"<<buf<<endl;

    return 0;
}

程式碼的執行結果如下:

child:receive message from pipe 1:I have liked yuki...
parent:receive message from pipe 2:I have liked yuki...

其中程式碼的流程是父程序建立了兩個管道,我們可以用fd1fd2表示,管道fd1負責父程序向子程序傳送資料,fd2負責子程序想父程序傳送資料。程序啟動後,子程序等待父程序通過管道fd1傳送資料,當子程序收到父程序的資料後,輸出訊息,並通過管道fd2回覆父程序,然後子程序退出,父程序收到子程序的響應後,輸出訊息並退出。

前面已經說了對管道的read會阻塞到管道中有資料為止,具體管道的readwrite的規則將會在後面介紹。

1.3 popenpclose函式

作為關於管道的一個例項,就是標準I/O函式庫提供的popen函式,該函式建立一個管道,並fork一個子程序,該子程序根據popen傳入的引數,關閉管道的對應端,然後執行傳入的shell命令,然後等待終止。

呼叫程序和fork的子程序之間形成一個管道。呼叫程序和執行shell命令的子程序之間的管道通訊是通過popen返回的FILE*來間接的實現的,呼叫程序通過標準檔案I/O來寫入或讀取管道。

下面是這兩個函式的宣告。

#include <stdio.h>

FILE *popen(const char *command, const char *type);
                          //成功返回標準檔案I/O指標,失敗返回NULL

int pclose(FILE *stream);
                          //成功返回shell的終止狀態,失敗返回-1

command:該傳入引數是一個shell命令列,這個命令是通過shell處理的。

type:該引數決定呼叫程序對要執行的command的處理,type有如下兩種情況:

  • type = “r”,呼叫程序將讀取command執行後的標準輸出,該標準輸出通過返回的FILE*來操作;
  • type = “w”,呼叫程序將寫command執行過程中的標準輸入;

pclose函式會關閉由popen建立的標準I/O流,等待其中的命令終止,然後返回shell的執行狀態。

下面是關於popen的測試程式碼:

#include <iostream>
#include <cstdio>

#include <unistd.h>

using namespace std;

int main()
{
    char *cmd = "ls /usr/local/bin ";

    FILE *p = popen(cmd, "r");
    char buf[256];

    while (fgets(buf, 256, p) != NULL)
    {
        cout<<buf;
    }  

    pclose(p);

    return 0;
}

程式的執行結果如下所示:

ccmake
cmake
cpack
CSGMP_CG_Server
CSGMP_Start.sh
ctest
...

程式的執行流程如下:呼叫程序執行popen時,會建立一個管道,然後fork生成一個子程序,子程序執行popen傳入的"ls /usr/local/bin" shell命令,子程序將執行結果通過管道傳遞給呼叫程序,呼叫程序通過標準檔案I/O來讀取管道中的資料,並輸出顯示。

相關推薦

Linux程序通訊管道FIFO

Linux程序間的通訊可以簡稱為IPC(Interprocess Communication),前面說過的 Linux的同步工具也是屬於IPC的一部分,這裡我想說的是通常意義的程序間的實際資料通。 1管道 管道是最早的UNIX IPC,所有的UNIX系統都支援這個IPC通訊機制。我們最常見到使用它的位置就是

Linux 程序通訊 ——訊號訊號量總結

現在最常用的程序間通訊的方式有:訊號,訊號量,訊息佇列,共享記憶體。       所謂程序通訊,就是不同程序之間進行一些"接觸",這種接觸有簡單,也有複雜。機制不同,複雜度也不一樣。通訊是一個廣義上的意義,不僅僅指傳遞一些massege。他們的使用方法是基本相同的,所以只要

Linux程序通訊--無名管道(pipe)有名管道FIFO通訊

管道通訊 管道是單向的、先進先出的,它把一個程序的輸出和另一個程序的輸入連線在一起。一個程序(寫程序)在管道的尾部寫入資料,另一個程序(讀程序)從管道的頭部讀出資料 管道建立 管道包括無名管道和有名管道兩種,前者用於父程序和子程序的通訊,後者可用於運行於同一系統中的任意兩個程序間

Linux 程序通訊:命名管道FIFO

一、簡介 由於管道(Pipe)只能應用於存在血緣關係的程序間通訊,為了突破這個限制,使用命名管道(FIFO)來實現 不相干程序間 的通訊。 FIFO 是 Linux 基礎檔案型別中的一種,它並不佔用磁碟上實際的資料塊,而僅僅是標識核心中的一條通道。各程序可以開啟

Linux 程序通訊管道 (Pipe)

一、簡介 管道(pipe) 是一種最基本的 IPC(Inter Process Communication) 機制,優點是簡單。 二、特點: 管道只適用於 存在血緣關係 的兩個程序之間通訊,因為只有存在血緣關係的兩個程序之間才能共享檔案描述符 管道分為兩端,一端

Linux 程序通訊 命名管道

#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> int main() { int fb =

Linux 程序通訊:記憶體共享(Shared Memory)

一、簡介 共享記憶體允許兩個程序訪問同一塊記憶體區域,它們使用同一個 key 值標記。 二、特點 優點: 通訊方便,兩個程序也是直接訪問同一塊記憶體區域,減少了資料複製的操作,速度上也有明顯優勢。 缺點: 沒有提供同步機制,往往需要我們使用其它(例如訊號)等手段實

Linux 程序通訊:記憶體對映(Memory Map)

一、簡介 正如其名(Memory Map),mmap 可以將某個裝置或者檔案對映到應用程序的記憶體空間中。通過直接的記憶體操作即可完成對裝置或檔案的讀寫。. 通過對映同一塊實體記憶體,來實現共享記憶體,完成程序間的通訊。由於減少了資料複製的次數,一定程度上提高了程序間通訊的效率。

程序通訊管道(PIPE)

在前面程序通訊概念和程序通訊方式,我們瞭解了程序通訊的簡單概念以及4種程序通訊的方式,今天我們將要通過具體例項來學習,理解程序通訊方式中的管道(PIPE)。 本文所有程式碼都在Ubuntu16.04測試。 我們在前面已經瞭解了常用的程序間通訊方式,它們大

linux程序通訊訊號燈(訊號量,semaphore)

訊號燈通訊,和一般意義的通訊不大一樣,通訊一般是用來收發資料,而訊號燈卻是用來控制多程序訪問共享資源的,利用這一功能,訊號量也就可以用做程序同步(實際上是執行緒間同步)。訊號燈的當前值、有幾個程序在等待當前值變為0等等,這些資訊,可隨時用watch -n 0.1 ipcs -

Linux程序通訊訊息佇列的雙向通訊

  上一篇部落格我寫了程序間通訊基於管道的通訊,但是管道的通訊無疑有很大的缺點,最顯著的就是隻能單向通訊,例如:server向client發訊息,client無法回覆;第二個就是隻能在有血緣關係的程序間進行通訊,雖然命名管道解決了第二點,但是第一點還是一個很大的

Linux程序通訊訊號

文章轉自   http://blog.csdn.net/maimang1001/article/details/16906451 鑑於後面把程序的形象給徹底毀掉了,我提前宣告一下,程序是有尊嚴的有節操的,當然大部分人可能也看不到毀形象那一段。為什麼介紹linux要從訊號

程序通訊管道--pipefifo使用

匿名管道pipe 函式原型: #include <unistd.h> int pipe(int fildes[2]); 引數說明 fildes是我們傳入的陣列,也是一個傳出引數。fildes[0]是讀端,fildes[1]是寫端。 返回值 成功呼叫返回0。 失敗呼叫返回-1且

Linux程序通訊管道通訊詳解

        在學習程序的時候,我們瞭解到了程序的獨立性:程序之間是相互獨立的,每個程序有自己的虛擬地址空間,並且虛擬地址空間通過頁表的對映,對映到屬於自己的實體記憶體上。並且各個程序之間互相不影響,執行自己的程式碼。    

程序通訊命名管道(FIFO)

匿名管道只能於有血緣關係的程序,那麼倆個沒有任何關係的程序怎麼通訊,這就出現了命名管道來克服這一問題。命名管道是一個裝置檔案,只要訪問該路徑,就能通過這個共享資源來互相通訊。FIFO是按照先進先出的原則工作的,第一個被寫入的資料第一個先被讀出。FIFO可被用於複製序列管道命

Linux程序通訊——管道(整理)

 程序間通訊 fork pipe pie_t 等用法(管道機制 通訊) 每個程序各自有不同的使用者地址空間,任 何一個程序的全域性變數在另一個程序中都看不到,所以程序之間要交換資料必須通過核心,在核心中開闢一塊緩衝 區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從

Linux -- 程序通訊管道

管道是Linux裡的一種檔案型別,同時也是Linux系統下程序間通訊的一種方式 建立一個管道檔案有兩種方式: 1.  Shell 下命令 mkfifo + filename,即建立一個有名管道 2.

Linux 程序通訊管道

程序之間的通訊之管道 目錄 1 無名管道    管道是一種最基本的IPC機制,作用於父子程序之間,完成資料傳遞。 管道有以下特性: 1.其本質是一個偽檔案(實為核心緩衝區)其本質是一個偽檔案(實為核心緩衝區) 2.由兩

Linux下的程序通訊管道

在Linux下,每個程序各自有不同的使用者地址空間,任何一個程序的全域性變數在另一個程序中都看不到所以進 程之間要交換資料必須通過核心,在核心中開闢一塊緩衝區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從核心緩衝區把資料讀走,核心提供的這種機制稱為程序間通

Linux 進程間通信管道(pipe),(fifo)

命名 som 新的 ima fcntl node hello 字符串 oot 無名管道(pipe) 管道可用於具有親緣關系進程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關系進程間的通信; 定義函數: int pipe(int