每個程序各自有不同的使用者位址空間,任何乙個程序的全域性變數在另乙個程序中都是看不到的。所以程序之間如果要交換資料就必須通過核心。
在核心中開闢一塊緩衝區,程序1把資料從使用者空間拷到核心緩衝區,程序2再從核心緩衝區把資料讀走,核心提供的這種機制稱為程序間通訊(ipc,interprocess communication)。
程序間通訊的本質,就是要讓不同的程序看到同乙份資源。
程序間的通訊方法有很多,今天只說管道。
管道分為兩種:匿名管道與命名管道。
匿名管道是一種最基本的ipc機制,由pipe函式建立:
呼叫pipe函式時在核心中開闢一塊緩衝區(稱為管道)用於通訊,它有乙個讀端乙個寫端,然後通過pipefd引數傳出給使用者程式兩個檔案描述符,pipefd[0]指向管道的讀端,fpipefd1]指向管道的寫端。
所以管道在使用者程式看起來就像乙個開啟的檔案,通過read(filedes[0]);或者write(filedes[1]);向這個檔案讀寫資料其實是在讀寫核心緩衝區。pipe函式呼叫成功返回0,呼叫失敗返回-1。 開闢了管道之後如何實現兩個程序間的通訊呢?比如可以按下面的步驟通訊。
父程序呼叫pipe開闢管道,得到兩個檔案描述符指向管道的兩端。父程序呼叫fork建立子程序,那麼子程序也有兩個檔案描述符指向同一管道。父程序關閉管道讀端,子程序關閉管道寫端(當然也可以反過來)。父程序可以往管道裡寫,子程序可以從管道裡讀,管道是用環形佇列實現的,資料從寫端流入,從讀端流出,這樣就實現了程序間通訊。因為管道是單向通訊的,即單工,所以父子程序必須關閉它們各自不需要的端。其次,匿名管道是通過子程序繼承父程序的檔案描述符表才得以實現父子程序共同看到乙份資源,所以匿名管道也就只能在有親緣關係的程序間實現通訊。
**實現:
#include
#include
#include
int main()
// 實現父程序寫,子程序讀
pid_t id = fork();
if (id < 0)
else if (id == 0) // child
else if (_s == 0)
else
}close(fd[0]);
} else // father
close(fd[1]); }
return 0;
}執行結果:
匿名管道的特點:
單向通訊具有親緣關係的程序間通訊管道生命週期隨程序(管道檔案描述符在程序結束後被關閉)面向位元組流的服務底層實現的同步機制,無需使用者在考慮(為空不允許讀,為滿不允許寫(阻塞))幾種特殊情況:
如果所有指向管道寫端的檔案描述符都關閉了(管道寫端的引用計數等於0),而仍然有程序從管道的讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會返回0,就像讀到檔案末尾一樣。如果有指向管道寫端的檔案描述符沒關閉(管道寫端的引用計數大於0),而持有管道寫端的程序也沒有向管道中寫資料,這時有程序從管道讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會阻塞,直到管道中有資料可讀了才讀取資料並返回。如果所有指向管道讀端的檔案描述符都關閉了(管道讀端的引用用計數等於0),這時有程序向管道的寫端write,那麼該程序會收到訊號sigpipe,通常會導致程序異常終止。如果有指向管道讀端的檔案描述符沒關閉(管道讀端的引用計數大於0),而持有管道讀端的程序也沒有從管道中讀資料,這時有程序向管道寫端寫資料,那麼在管道被寫滿時再次write會阻塞,直到管道中有空位置了才寫入資料並返回。匿名管道的缺點就是只能在有親緣關係的程序間進行通訊,針對這個缺陷,又提出來了命名管道(fifo)的概念。fifo不同於管道之處在於它提供乙個路徑名與之關聯,以fifo的檔案形式儲存於檔案系統中。命名管道是乙個裝置檔案,因此,即使程序與建立fifo的程序不存在親緣關係,只要可以訪問該路徑,就能夠通過fifo
相互通訊。值得注意的是,fifo(first input first output)總是按照先進先出的原則工作,第乙個被寫入的資料將首先從管道中讀出。
建立命名管道的方式無非也就是那兩種:命令和函式。而且命令和函式對應的名字是一樣的,mkfifo(mknod)命令/函式。
示例**:
server:
#include
#include
#include
#include
#include
#include
int main()
int fd = open("./.fifo", o_wronly);
if (fd < 0)
int cnt = 0;
char *msg = "hello world";
while (cnt++ < 5)
close(fd);
return 0;
}client:
#include
#include
#include
#include
#include
#include
int main()
int cnt = 0;
char buf[128];
while (cnt++ < 5)
else if (_s == 0)
else
sleep(1);
} close(fd);
return 0;
}執行結果:
命名管道建立後就可以使用了,命名管道和管道的使用方法基本是相同的。只是使用命名管道時,必須先呼叫open()將其開啟。因為命名管道是乙個存在於硬碟上的檔案,而管道是存在於記憶體中的特殊檔案。需要注意的是,呼叫open()開啟命名管道的程序可能會被阻塞。但如果同時用讀寫方式(o_rdwr)開啟,則一定不會導致阻塞;如果以唯讀方式(o_rdonly)開啟,則呼叫open()函式的程序將會被阻塞直到有寫方開啟管道;同樣以寫方式(o_wronly)開啟也會阻塞直到有讀方式開啟道。
命名管道與匿名管道不同的地方在於即使沒有親緣關係,也可以通過fifo來通訊,且管道的生命週期不再是隨程序,因為即使命名管道檔案描述符被關閉,fifo依然存在於磁碟上,是乙個檔案。
程序間通訊之管道篇
這裡我們談談程序間互動的機制,這裡不同於使用訊號來讓程序間傳送訊息。當從乙個程序連線資料流到另乙個程序時,我們使用術語管道 pipe 我們通常是把乙個程序的輸出通過管道連線 到另乙個程序的輸入。我們來看看底層的pipe 函式呼叫。通過這個函式在兩個程式間傳遞資料不需要啟動乙個shell來解釋請求的命...
程序間通訊之管道篇
在介紹管道之前,我們先了解一下程序間通訊。程序間通訊目的 程序間通訊的分類 本篇部落格將著重介紹管道。什麼是管道?匿名管道 include h 功能 建立一無名管道 原型 int pipe int fd 2 引數,fd檔案描述符陣列,fd 0 表示讀端,fd 1 表示寫段 返回值 成功返回0,失敗返...
程序間通訊 之 管道
一 無名管道 特點 具有親緣關係的程序間通訊,但不僅僅指父子程序之間哦。1 無名管道的建立 int pipe int pipefd 引數 pipefd 陣列的首位址 返回值 成功返回0,失敗返回 1 注意 無名管道存在核心空間,建立成功會給使用者空間兩個檔案描述符,fd 0 讀管道 fd 1 寫管道...