程序間通訊(一)

2022-08-05 17:57:14 字數 3457 閱讀 9427

1.程序是一種單執行流,每個程序都私有/獨佔乙份系統資源,**段共享但是資料段不共享,子程序寫資料時會觸發寫實拷貝,從而保證資源獨享。總的來說 每個程序各自有不同的使用者位址空間,任何乙個程序的全域性變數在另乙個程序中都看不到 。

所以程序之間要交換資料必須通過核心,在核心中開闢一塊緩衝區,程序1把資料從使用者空間 拷到核心緩衝區,程序2再從核心緩衝區把資料讀走,核心提供的這種機制稱為程序間通訊 如圖所示:

程序間通訊(ipc,interprocess communication)的方式:

1.管道:匿名管道、命名管道

2.xsi ipc:訊息佇列、訊號量、共享記憶體

xsi ipc,依託識別符號和鍵來實現的,如同管道靠檔案描述符來實現一樣。

xsi ipc使用一般步驟:

1)ipc物件程序內部用識別符號identifier,程序外部標識用key

2)首先用semget,shmget,msgget等函式根據key建立或獲取ipc物件的identifier

3)然後根據identifier用semctrl,shmctrl等控制函式做某些修改,這步可選

4)最後用各個ipc特有操作函式如semop,shmat等函式操作)

匿名管道(pipe)

調⽤用pipe函式時在核心中開闢一塊緩衝區(稱為管道)用於通訊,它有乙個讀端乙個寫端,然後 通過filedes引數傳出給使用者程式兩個檔案描述符,filedes[0]指向管道的讀端,filedes[1]指向 管道 的寫端(很好記,就像0是標準輸入1是標準輸出一樣)。所以管道在使用者程式看起來就像乙個開啟的檔案,通過read(filedes[0]);或者write(filedes[1]);向這個檔案讀寫資料其實是在讀寫核心緩衝區。pipe函式呼叫成功返回0,呼叫失敗返回-1。

1. 父程序呼叫pipe開闢管道,得到兩個檔案描述符指向管道的兩端。 

2. 父程序呼叫fork建立子程序,那麼子程序也有兩個檔案描述符指向同一管道。 

3. 父程序關閉管道讀端,子程序關閉管道寫端。父程序可以往管道裡寫,子程序可以從管道裡讀,管道是用環形佇列實現的,資料從寫端流入從讀端流出,這樣就實現了程序間通訊

int test1()         //test creat ipc fun "pipe()"

pid_t id = fork();

if (id < 0)

else if (id == 0)         //child only write,father only read

}else

}return 0;

}使用管道有一些限制:

兩個程序通過乙個管道只能實現單向通訊。比如上面的例子,父程序寫子程序讀,如果有時候也需要子程序寫父程序讀,就必須另開乙個管道。(原因:管道是一種半雙工方式,即對於程序來說,要麼只能讀管道,要麼只能寫管道。不允許對管道又讀又寫)《半雙工資料傳輸允許資料在兩個方向上傳輸,但是,在某一時刻,只允許資料在乙個方向上傳輸》

管道的讀寫端通過開啟的檔案描述符來傳遞,因此要通訊的兩個程序必須從它們的公共祖先 那⾥裡繼承管道檔案描述符。

父程序fork兩次,把檔案描述符傳給兩個子程序,然後兩個子程序之間通訊, 總之需要通過fork傳遞檔案描述符使兩個程序都能訪問同一管道,它們才能通訊。也就是說,管道通訊是需要程序之間有血緣關係。

⽤用管道需要注意以下4種特殊情況(假設都是阻塞i/o操作,沒有設定o_nonblock標誌):  

1. 如果所有指向管道寫端的檔案描述符都關閉了(管道寫端的引⽤用計數等於0),而仍然有程序 從管道的讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會返回0,就像 讀到檔案 末尾一樣。

2. 如果有指向管道寫端的檔案描述符沒關閉(管道寫端的引用計數⼤大於0),而持有管道寫端的程序也沒有向管道中寫資料,這時有程序從管道讀端讀資料,那麼管道中剩餘的資料都被讀取後,再次read會阻塞,直到管道中有資料可讀了才讀取資料並返回 

3. 如果所有指向管道讀端的檔案描述符都關閉了(管道讀端的引用計數等於0),這時有程序向管道的寫端write,那麼該程序會收到訊號sigpipe,通常會導致程序異常終止。

4. 如果有指向管道讀端的檔案描述符沒關閉(管道讀端的引⽤用計數⼤大於0),而持有管道讀端的程序也沒有從管道中讀資料,這時有程序向管道寫端寫資料,那麼在管道被寫滿時再次write會阻塞,直到管道中有空位置了才寫入資料並返回。

命名管道(fifo) 檔案系統中的路徑名是全域性的,各程序都可以訪問,因此可以⽤用檔案系統中的路徑名來標識一 個ipc通道。  命名管道也被稱為fifo檔案,它是一種特殊型別的檔案,它在檔案系統中以檔名的形式存在,但是它的行為卻和之前所講的沒有名字的管道(匿名管道)類似。

由於linux中所有的事物都可被視為檔案,所以對命名管道的使用也就變得與檔案操作非常的統一,也使它的使用非常方便,同時我們也可以像平常的檔名一樣在命令中使用。 建立命名管道 我們可以使用兩下函式之一來建立乙個命名管道,他們的原型如下:

#include

#include

int mkfifo(const char *filename, mode_t mode);  

int mknod(const char *filename, mode_t mode | s_ififo, (dev_t)0);  

這兩個函式都能建立乙個fifo檔案,注意是建立乙個真實存在於檔案系統中的檔案, filename指定了檔名,而mode則指定了檔案的讀寫許可權。

mknod是比較老的函式,而使 用mkfifo函式更加簡單和規範,所以建議在可能的情況下,盡量使⽤用mkfifo而不是mknod。

int main()

char buf[_size_];

memset(buf, '\0' ,sizeof (buf));

while (1)

printf( "%s\n" ,buf);

if (strncmp(buf,"quit" ,4) == 0)

break ;

}close(fp);

return 0;

}int main()

int fp = open(_path_,o_wronly);

if (fp == -1)

char buf[_size_];

memset(buf, '\0' ,sizeof (buf));

while (1)

if (strncmp(buf,"quit" ,4) == 0)

break ;

}close(fp);

return 0;

}

程序間通訊(一)

為什麼程序間要通訊?1 資料傳輸 2 資源共享 3 通知事件 4 程序控制 程序間通訊方式 管道通訊 共享記憶體 訊息佇列 訊號通訊 一 管道通訊 管道是單向的 先進先出的,它把乙個程序的輸出和另乙個程序的輸入連線在一起。乙個程序 寫程序 在管道尾部寫入資料,另乙個程序 讀程序 從管道的頭部讀出資料...

程序間通訊(一)

半雙工管道 fifo 全雙工管道 命名全雙工管道 訊息佇列 訊號量 共享記憶體 套接字 多機其它為單機 管道 包括無名管道 命名管道 訊息佇列 訊號量共享儲存 scoket streams 等。其中,scoket和stream支援不同主機上的兩個程序ipc。一 管道 管道,通常指無名管道,是unix...

程序間通訊 一)

測試 例子 從鍵盤讀取資料,寫入管道,讀取管道,寫到螢幕 include include include include intmain void memset buf,0x00 sizeof buf read from pipeif len read fds 0 buf,100 1 write t...