Linux程序間的通訊方式和原理

2022-08-16 01:48:14 字數 4401 閱讀 5317

管道包括三種:

管道是如何通訊的

管道是由核心管理的乙個緩衝區,相當於我們放入記憶體中的乙個紙條。管道的一端連線乙個程序的輸出。這個程序會向管道中放入資訊。管道的另一端連線乙個程序的輸入,這個程序取出被放入管道的資訊。乙個緩衝區不需要很大,它被設計成為環形的資料結構,以便管道可以被迴圈利用。當管道中沒有資訊的話,從管道中讀取的程序會等待,直到另一端的程序放入資訊。當管道被放滿資訊的時候,嘗試放入資訊的程序會等待,直到另一端的程序取出資訊。當兩個程序都終結的時候,管道也自動消失。

管道是如何建立的

從原理上,管道利用fork機制建立,從而讓兩個程序可以連線到同乙個pipe上。最開始的時候,上面的兩個箭頭都連線在同乙個程序process 1上(連線在process 1上的兩個箭頭)。當fork複製程序的時候,會將這兩個連線也複製到新的程序(process 2)。隨後,每個程序關閉自己不需要的乙個連線 (兩個黑色的箭頭被關閉; process 1關閉從pipe來的輸入連線,process 2關閉輸出到pipe的連線),這樣,剩下的紅色連線就構成了如上圖的pipe。

有兩個 file 資料結構,但它們定義檔案操作例程位址是不同的,其中乙個是向管道中寫入資料的例程位址,而另乙個是從管道中讀出資料的例程位址。這樣,使用者程式的系統呼叫仍然是通常的檔案操作,而核心卻利用這種抽象機制實現了管道這一特殊操作。

關於管道的讀寫

管道實現的源**在fs/pipe.c中,在pipe.c中有很多函式,其中有兩個函式比較重要,即管道讀函式pipe_read()和管道寫函式pipe_wrtie()。管道寫函式通過將位元組複製到 vfs 索引節點指向的物理記憶體而寫入資料,而管道讀函式則通過複製物理記憶體中的位元組而讀出資料。當然,核心必須利用一定的機制同步對管道的訪問,為此,核心使用了鎖、等待佇列和訊號。

當寫程序向管道中寫入時,它利用標準的庫函式write(),系統根據庫函式傳遞的檔案描述符,可找到該檔案的 file 結構。file 結構中指定了用來進行寫操作的函式(即寫入函式)位址,於是,核心呼叫該函式完成寫操作。寫入函式在向記憶體中寫入資料之前,必須首先檢查 vfs 索引節點中的資訊,同時滿足如下條件時,才能進行實際的記憶體複製工作:

如果同時滿足上述條件,寫入函式首先鎖定記憶體,然後從寫程序的位址空間中複製資料到記憶體。否則,寫入程序就休眠在 vfs 索引節點的等待佇列中,接下來,核心將呼叫排程程式,而排程程式會選擇其他程序執行。寫入程序實際處於可中斷的等待狀態,當記憶體中有足夠的空間可以容納寫入資料,或記憶體被解鎖時,讀取程序會喚醒寫入程序,這時,寫入程序將接收到訊號。當資料寫入記憶體之後,記憶體被解鎖,而所有休眠在索引節點的讀取程序會被喚醒。

管道的讀取過程和寫入過程類似。但是,程序可以在沒有資料或記憶體被鎖定時立即返回錯誤資訊,而不是阻塞該程序,這依賴於檔案或管道的開啟模式。反之,程序可以休眠在索引節點的等待佇列中等待寫入程序寫入資料。當所有的程序完成了管道操作之後,管道的索引節點被丟棄,而共享資料頁也被釋放。

linux函式原型

#include int pipe(int filedes[2]);

filedes[0]用於讀出資料,讀取時必須關閉寫入端,即close(filedes[1]);

filedes[1]用於寫入資料,寫入時必須關閉讀取端,即close(filedes[0])。

程式例項:

int main(void)

if((pid = fork()) 0) /* 父程序把檔案描述符複製給子程序 */

exit(1);

else if(pid > 0)

else

exit(0);

}

由於基於fork機制,所以管道只能用於父程序和子程序之間,或者擁有相同祖先的兩個子程序之間 (有親緣關係的程序之間)。為了解決這一問題,linux提供了fifo方式連線程序。fifo又叫做命名管道(named pipe)。

實現原理

fifo (first in, first out)為一種特殊的檔案型別,它在檔案系統中有對應的路徑。當乙個程序以讀(r)的方式開啟該檔案,而另乙個程序以寫(w)的方式開啟該檔案,那麼核心就會在這兩個程序之間建立管道,所以fifo實際上也由核心管理,不與硬碟打交道。之所以叫fifo,是因為管道本質上是乙個先進先出的佇列資料結構,最早放入的資料被最先讀出來,從而保證資訊交流的順序。fifo只是借用了檔案系統(file system,命名管道是一種特殊型別的文��,因為linux中所有事物都是檔案,它在檔案系統中以檔名的形式存在。)來為管道命名。寫模式的程序向fifo檔案中寫入,而讀模式的程序從fifo檔案中讀出。當刪除fifo檔案時,管道連線也隨之消失。fifo的好處在於我們可以通過檔案的路徑來識別管道,從而讓沒有親緣關係的程序之間建立連線

函式原型:

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

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

其中filename是被建立的檔名稱,mode表示將在該檔案上設定的許可權位和將被建立的檔案型別(在此情況下為s_ififo),dev是當建立裝置特殊檔案時使用的乙個值。因此,對於先進先出檔案它的值為0。

程式例項:

#include #include #include #include int main()  

exit(exit_success);

}

參考文獻

linux程序間通訊之管道(pipe)、命名管道(fifo)與訊號(signal)

什麼是訊號量

為了防止出現因多個程式同時訪問乙個共享資源而引發的一系列問題,我們需要一種方法。比如在任一時刻只能有乙個執行執行緒訪問**的臨界區域。臨界區域是指執行資料更新的**需要獨佔式地執行。而訊號量就可以提供這樣的一種訪問機制,讓乙個臨界區同一時間只有乙個執行緒在訪問它,也就是說訊號量是用來調協程序對共享資源的訪問的。

訊號量是乙個特殊的變數,程式對其訪問都是原子操作,且只允許對它進行等待(即p(訊號變數))和傳送(即v(訊號變數))資訊操作。最簡單的訊號量是只能取0和1的變數,這也是訊號量最常見的一種形式,叫做二進位制訊號量。而可以取多個正整數的訊號量被稱為通用訊號量。

訊號量的工作原理

由於訊號量只能進行兩種操作等待和傳送訊號,即p(sv)和v(sv),他們的行為是這樣的:

舉個例子,就是兩個程序共享訊號量sv,一旦其中乙個程序執行了p(sv)操作,它將得到訊號量,並可以進入臨界區,使sv減1。而第二個程序將被阻止進入臨界區,因為當它試圖執行p(sv)時,sv為0,它會被掛起以等待第乙個程序離開臨界區域並執行v(sv)釋放訊號量,這時第二個程序就可以恢復執行。

linux的訊號量機制

linux提供了一組精心設計的訊號量介面來對訊號進行操作,它們不只是針對二進位制訊號量,下面將會對這些函式進行介紹,但請注意,這些函式都是用來對成組的訊號量值進行操作的。它們宣告在標頭檔案sys/sem.h中。

semget函式

它的作用是建立乙個新訊號量或取得乙個已有訊號量,原型為:

int semget(key_t key, int num_sems, int sem_flags);  

semget函式成功返回乙個相應訊號識別符號(非零),失敗返回-1.

semop函式

它的作用是改變訊號量的值,原型為:

int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);  

sem_id是由semget返回的訊號量識別符號,sembuf結構的定義如下:

struct sembuf;  

semctl函式
int semctl(int sem_id, int sem_num, int command, ...);  

如果有第四個引數,它通常是乙個union semum結構,定義如下:

union semun;  

前兩個引數與前面乙個函式中的一樣,command通常是下面兩個值中的其中乙個 

setval:用來把訊號量初始化為乙個已知的值。p 這個值通過union semun中的val成員設定,其作用是在訊號量第一次使用前對它進行設定。 

ipc_rmid:用於刪除乙個已經無需繼續使用的訊號量識別符號。

linux 程序間通訊方式

1 無名管道通訊 無名管道 pipe 管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有親緣關係的程序間使用。程序的親緣關係通常是指父子程序關係。2 高階管道通訊 高階管道 popen 將另乙個程式當做乙個新的程序在當前程式程序中啟動,則它算是當前程式的子程序,這種方式我們成為高階管道方式...

Linux程序間通訊方式

目錄前言 一 程序間通訊的目的 二 linux程序間通訊方式簡介 程序間的通訊就是在不同程序之間傳播或者交換資訊。程序的使用者空間是相互獨顯然可以體用這幾樣的立的,一般而言是不能互相訪問的,唯一的例外是共享空間。但是系統空間卻是 公共場所 所以核心顯然可以提供這樣的條件。除此以外,那就是雙方都可以訪...

linux程序間通訊方式

1 管道 pipe 2 命名管道 named pipe 3 訊號 signal 4 訊息 message 佇列 5 共享記憶體 6 訊號量 semaphore 7 套接字 socket 1 管道 pipe 管道可用於具有親緣關係程序間的通訊,允許乙個程序和另乙個與它有共同祖先的程序之間進行通訊。2 ...