1. 程式人生 > >程序間的五種通訊方式介紹

程序間的五種通訊方式介紹

程序間通訊(IPC,InterProcess Communication)是指在不同程序之間傳播或交換資訊。

IPC的方式通常有管道(包括無名管道和命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等。其中 Socket和Streams支援不同主機上的兩個程序IPC。

以Linux中的C語言程式設計為例。

一、管道

管道,通常指無名管道,是 UNIX 系統IPC最古老的形式。

1、特點:

  1. 它是半雙工的(即資料只能在一個方向上流動),具有固定的讀端和寫端。

  2. 它只能用於具有親緣關係的程序之間的通訊(也是父子程序或者兄弟程序之間)。

  3. 它可以看成是一種特殊的檔案,對於它的讀寫也可以使用普通的read、write 等函式。但是它不是普通的檔案,並不屬於其他任何檔案系統,並且只存在於記憶體中。

一、管道

管道,通常指無名管道,是 UNIX 系統IPC最古老的形式。

1、特點:

  1. 它是半雙工的(即資料只能在一個方向上流動),具有固定的讀端和寫端。

  2. 它只能用於具有親緣關係的程序之間的通訊(也是父子程序或者兄弟程序之間)。

  3. 它可以看成是一種特殊的檔案,對於它的讀寫也可以使用普通的read、write 等函式。但是它不是普通的檔案,並不屬於其他任何檔案系統,並且只存在於記憶體中。

2、原型:

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

當一個管道建立時,它會建立兩個檔案描述符:fd[0]

為讀而開啟,fd[1]為寫而開啟。如下圖:

要關閉管道只需將這兩個檔案描述符關閉即可。

3、例子

單個程序中的管道幾乎沒有任何用處。所以,通常呼叫 pipe 的程序接著呼叫 fork,這樣就建立了父程序與子程序之間的 IPC 通道。如下圖所示:

若要資料流從父程序流向子程序,則關閉父程序的讀端(fd[0])與子程序的寫端(fd[1]);反之,則可以使資料流從子程序流向父程序。

複製程式碼
 1 #include<stdio.h>
 2 #include<unistd.h>
 3 
 4 int main()
 5 {
 6     int fd[2];  //
兩個檔案描述符 7 pid_t pid; 8 char buff[20]; 9 10 if(pipe(fd) < 0) // 建立管道 11 printf("Create Pipe Error!\n"); 12 13 if((pid = fork()) < 0) // 建立子程序 14 printf("Fork Error!\n"); 15 else if(pid > 0) // 父程序 16 { 17 close(fd[0]); // 關閉讀端 18 write(fd[1], "hello world\n", 12); 19 } 20 else 21 { 22 close(fd[1]); // 關閉寫端 23 read(fd[0], buff, 20); 24 printf("%s", buff); 25 } 26 27 return 0; 28 }
複製程式碼

二、FIFO

FIFO,也稱為命名管道,它是一種檔案型別。

1、特點

  1. FIFO可以在無關的程序之間交換資料,與無名管道不同。

  2. FIFO有路徑名與之相關聯,它以一種特殊裝置檔案形式存在於檔案系統中。

2、原型

1 #include <sys/stat.h>
2 // 返回值:成功返回0,出錯返回-1
3 int mkfifo(const char *pathname, mode_t mode);

其中的 mode 引數與open函式中的 mode 相同。一旦建立了一個 FIFO,就可以用一般的檔案I/O函式操作它。

當 open 一個FIFO時,是否設定非阻塞標誌(O_NONBLOCK)的區別:

  • 若沒有指定O_NONBLOCK(預設),只讀 open 要阻塞到某個其他程序為寫而開啟此 FIFO。類似的,只寫 open 要阻塞到某個其他程序為讀而開啟它。

  • 若指定了O_NONBLOCK,則只讀 open 立即返回。而只寫 open 將出錯返回 -1 如果沒有程序已經為讀而開啟該 FIFO,其errno置ENXIO。

3、例子

FIFO的通訊方式類似於在程序中使用檔案來傳輸資料,只不過FIFO型別檔案同時具有管道的特性。在資料讀出時,FIFO管道中同時清除資料,並且“先進先出”。下面的例子演示了使用 FIFO 進行 IPC 的過程:

write_fifo.c

複製程式碼
 1 #include<stdio.h>
 2 #include<stdlib.h>   // exit
 3 #include<fcntl.h>    // O_WRONLY
 4 #include<sys/stat.h>
 5 #include<time.h>     // time
 6 
 7 int main()
 8 {
 9     int fd;
10     int n, i;
11     char buf[1024];
12     time_t tp;
13 
14     printf("I am %d process.\n", getpid()); // 說明程序ID
15     
16     if((fd = open("fifo1", O_WRONLY)) < 0) // 以寫開啟一個FIFO 
17     {
18         perror("Open FIFO Failed");
19         exit(1);
20     }
21 
22     for(i=0; i<10; ++i)
23     {
24         time(&tp);  // 取系統當前時間
25         n=sprintf(buf,"Process %d's time is %s",getpid(),ctime(&tp));
26         printf("Send message: %s", buf); // 列印
27         if(write(fd, buf, n+1) < 0)  // 寫入到FIFO中
28         {
29             perror("Write FIFO Failed");
30             close(fd);
31             exit(1);
32         }
33         sleep(1);  // 休眠1秒
34     }
35 
36     close(fd);  // 關閉FIFO檔案
37     return 0;
38 }
複製程式碼

read_fifo.c

複製程式碼
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<errno.h>
 4 #include<fcntl.h>
 5 #include<sys/stat.h>
 6 
 7 int main()
 8 {
 9     int fd;
10     int len;
11     char buf[1024];
12 
13     if(mkfifo("fifo1", 0666) < 0 && errno!=EEXIST) // 建立FIFO管道
14         perror("Create FIFO Failed");
15 
16     if((fd = open("fifo1", O_RDONLY)) < 0)  // 以讀開啟FIFO
17     {
18         perror("Open FIFO Failed");
19         exit(1);
20     }
21     
22     while((len = read(fd, buf, 1024)) > 0) // 讀取FIFO管道
23         printf("Read message: %s", buf);
24 
25     close(fd);  // 關閉FIFO檔案
26     return 0;
27 }
複製程式碼

在兩個終端裡用 gcc 分別編譯執行上面兩個檔案,可以看到輸出結果如下:

複製程式碼
 1 [[email protected]]$ ./write_fifo 
 2 I am 5954 process.
 3 Send message: Process 5954's time is Mon Apr 20 12:37:28 2015
 4 Send message: Process 5954's time is Mon Apr 20 12:37:29 2015
 5 Send message: Process 5954's time is Mon Apr 20 12:37:30 2015
 6 Send message: Process 5954's time is Mon Apr 20 12:37:31 2015
 7 Send message: Process 5954's time is Mon Apr 20 12:37:32 2015
 8 Send message: Process 5954's time is Mon Apr 20 12:37:33 2015
 9 Send message: Process 5954's time is Mon Apr 20 12:37:34 2015
10 Send message: Process 5954's time is Mon Apr 20 12:37:35 2015
11 Send message: Process 5954's time is Mon Apr 20 12:37:36 2015
12 Send message: Process 5954's time is Mon Apr 20 12:37:37 2015
複製程式碼 複製程式碼
 1 [[email protected]]$ ./read_fifo 
 2 Read message: Process 5954's time is Mon Apr 20 12:37:28 2015
 3 Read message: Process 5954's time is Mon Apr 20 12:37:29 2015
 4 Read message: Process 5954's time is Mon Apr 20 12:37:30 2015
 5 Read message: Process 5954's time is Mon Apr 20 12:37:31 2015
 6 Read message: Process 5954's time is Mon Apr 20 12:37:32 2015
 7 Read message: Process 5954's time is Mon Apr 20 12:37:33 2015
 8 Read message: Process 5954's time is Mon Apr 20 12:37:34 2015
 9 Read message: Process 5954's time is Mon Apr 20 12:37:35 2015
10 Read message: Process 5954's time is Mon Apr 20 12:37:36 2015
11 Read message: Process 5954's time is Mon Apr 20 12:37:37 2015
複製程式碼

上述例子可以擴充套件成 客戶程序—伺服器程序 通訊的例項,write_fifo的作用類似於客戶端,可以開啟多個客戶端向一個伺服器傳送請求資訊,read_fifo類似於伺服器,它適時監控著FIFO的讀端,當有資料時,讀出並進行處理,但是有一個關鍵的問題是,每一個客戶端必須預先知道伺服器提供的FIFO介面,下圖顯示了這種安排:

三、訊息佇列

訊息佇列,是訊息的連結表,存放在核心中。一個訊息佇列由一個識別符號(即佇列ID)來標識。

1、特點

  1. 訊息佇列是面向記錄的,其中的訊息具有特定的格式以及特定的優先順序

  2. 訊息佇列獨立於傳送與接收程序。程序終止時,訊息佇列及其內容並不會被刪除。

  3. 訊息佇列可以實現訊息的隨機查詢,訊息不一定要以先進先出的次序讀取,也可以按訊息的型別讀取。

2、原型

複製程式碼
1 #include <sys/msg.h>
2 // 建立或開啟訊息佇列:成功返回佇列ID,失敗返回-1
3 int msgget(key_t key, int flag);
4 // 新增訊息:成功返回0,失敗返回-1
5 int msgsnd(int msqid, const void *ptr, size_t size, int flag);
6 // 讀取訊息:成功返回訊息資料的長度,失敗返回-1
7 int msgrcv(int msqid, void *ptr, size_t size, long type,int flag);
8 // 控制訊息佇列:成功返回0,失敗返回-1
9 int msgctl(int msqid, int cmd, struct msqid_ds *buf);
複製程式碼

在以下兩種情況下,msgget將建立一個新的訊息佇列:

  • 如果沒有與鍵值key相對應的訊息佇列,並且flag中包含了IPC_CREAT標誌位。
  • key引數為IPC_PRIVATE

函式msgrcv在讀取訊息佇列時,type引數有下面幾種情況:

  • type == 0,返回佇列中的第一個訊息;
  • type > 0,返回佇列中訊息型別為 type 的第一個訊息;
  • type < 0,返回佇列中訊息型別值小於或等於 type 絕對值的訊息,如果有多個,則取型別值最小的訊息。

可以看出,type值非 0 時用於以非先進先出次序讀訊息。也可以把 type 看做優先順序的權值。(其他的引數解釋,請自行Google之)

3、例子

下面寫了一個簡單的使用訊息佇列進行IPC的例子,服務端程式一直在等待特定型別的訊息,當收到該型別的訊息以後,傳送另一種特定型別的訊息作為反饋,客戶端讀取該反饋並打印出來。

msg_server.c

相關推薦

作業系統 程序通訊方式介紹

程序間通訊(IPC,InterProcess Communication)是指在不同程序之間傳播或交換資訊。 IPC的方式通常有管道(包括無名管道和命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等。其中 Socket和Streams支援不同主機上的兩個程序IPC。 以Linux中的C語

程序通訊方式介紹

程序間通訊(IPC,InterProcess Communication)是指在不同程序之間傳播或交換資訊。 IPC的方式通常有管道(包括無名管道和命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等。其中 Socket和Streams支援不同主機上的兩個程序IPC。 以Linux中

程序8通訊方式

 由於記憶體管理的一些機制,導致兩個程序間並不能直接的進行通訊(在獨立的使用者空間),因此我們需要利用一些介質來完成兩個程序之間的通訊。以下是常用的8種程序間通訊方式。 1套接字 。1訊息佇列。2管道。2。訊號2。記憶體 。。。 套接字( socket ): 套解口也是一

程序通訊方式

一、管道 1、什麼是管道 我們把一個程序連線到另一個程序的資料流稱為一個管道。它是最古老的程序通訊形式。 2、原型(匿名管道): #include <unistd.h> 功能:建立⼀⽆名管道 原型 int pipe(int fd[2]); 引數 fd:⽂件

iOS App常用的通訊方式

iOS系統是相對封閉的系統,App各自在各自的沙盒(sandbox)中執行,每個App都只能讀取iPhone上iOS系統為該應用程式程式建立的資料夾AppData下的內容,不能隨意跨越自己的沙盒去訪問別的App沙盒中的內容。 所以iOS 的系統中進行App間通訊的方

小程式自定義元件及元件通訊方式

小程式經常會用到自定義元件,今天來說下五星評論自定義元件,可以單純顯示評分也可以進行評分,及元件間兩種通訊方式 一、在你的專案中根目錄新建components目錄,在components目錄下新建starComment目錄,然後右鍵點選新建Component,會出現如下目錄結構 二、在starComp

詳解Linux中程序的常用通訊方式

1、無名管道(Pipe)及有名管道(Named Pipe) ——管道是Linux中基於檔案描述符的程序間通訊方式之一,它把一個程式的輸出直接連線到另一個程式的輸入。 無名管道:用於具有親緣關係程序間的通訊。  (不常用) 特點: 僅用於父子或者兄弟程序之間通訊半雙工通訊

iOS app之間常用的通訊方式

iOS系統的Keychain是一個安全的儲存容器,它本質上就是一個sqllite資料庫,它的位置儲存在/private/var/Keychains/keychain-2.db,不過它所儲存的所有資料都是經過加密的,可以用來為不同的app儲存敏感資訊,比如使用者名稱,密碼等。iOS系統自己也用keychain

面試題2:程序常用的通訊方式有哪些?

程序間通訊(IPC,InterProcess Communication)是指在不同程序之間傳播或交換資訊。 IPC的方式通常有管道(包括無名管道和命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等。其中 Socket和Streams支援不同主機上的兩個

[作業系統原理] 程序之間8通訊方式

 程序間通訊就是在不同程序之間傳播或交換資訊,那麼不同程序之間存在著什麼雙方都可以訪問的介質呢?程序的使用者空間是互相獨立的,一般而言是不能互相訪問的,唯一的例外是共享記憶體區。但是,系統空間卻是“公共場所”,所以核心顯然可以提供這樣的條件。除此以外,那就是雙方都可以訪

程序、執行緒的幾通訊方式

一、程序通訊 幾種程序間的通訊方式 (1) 管道(pipe):管道是一種半雙工的通訊方式,資料只能單向流動,而且只能在具有血緣關係的程序間使用。程序的血緣關係通常指父子程序關係。 (2)有名管道(named pipe):有名管道也是半雙工的通訊方式,但是它允許無

Python學習【第20篇】:互斥鎖以及程序之間的三通訊方式(IPC)以及生產者個消費者模型 python併發程式設計之多程序1-----------互斥鎖與程序通訊

python併發程式設計之多程序1-----------互斥鎖與程序間的通訊 一、互斥鎖 程序之間資料隔離,但是共享一套檔案系統,因而可以通過檔案來實現程序直接的通訊,

程序之間的8通訊方式

現在最常用的程序間通訊的方式有訊號、資訊量、訊息佇列、共享記憶體等。 百度經驗有介紹8種 無名管道(pipe),高階管道(popen)、有名管道(nemed pipe)、訊息佇列(message queue)、訊號量(semophore)、訊號(sinal)、共享記憶體(s

【協議分析】HTTP響應頭中的2編碼方式介紹

href intro feo 發送 文檔 bsp firefox cep 目前 HTTP 1.1中有兩個實體頭(Entity-Header)直接與編碼相關,分別為Content-Encoding和Transfer-Encoding。 先說Content-Encodin

[Linux]PHP-FPM與NGINX的兩通訊方式

rom code pan ESS write 訪問權限 nec ner div 一、通過監聽TCP端口通訊 php-fpm.d/www.conf ; The address on which to accept FastCGI requests. ; Valid synt

利用管道實現程序的單向通訊

管道是程序間通訊的最原始方式,今天我們利用管道的程序間通訊,來實現簡單的程序間單向通訊 首先我們需要了解命名管道的一些特性命名管道的使用與建立 然後建立一個fifo_c的檔案來實現輸入資料和傳送資料 /*這是一個命名管道的實現,往命名管道中寫入資料,並且傳送給另一個程序 *

分散式鎖簡單三實現方式介紹

版權宣告:本文為博主原創文章,未經博主允許不得轉載。    https://blog.csdn.net/u010870518/article/details/79036337 很多小夥伴在學習Java的時候,總是感覺Java多執行緒在實際的業務中很少使用,以至於不會花太

IO模型介紹和對比

前言 unix提供的IO模型有幾種,分別有哪些? 各種IO模型的特點是什麼?他們有什麼區別? 阻塞,非阻塞,同步,非同步的區別? epoll為什麼高效? 概述 普通輸入操作包含的步驟 等待資料準備好 從核心向程序複製資料 網路資料輸入包含的步驟 等待資料從

HTML+CSS 佈局方式

已知佈局元素的高度,寫出三欄佈局,要求左欄、右欄寬度各為300px,中間自適應。 一、浮動佈局 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <tit

轉 Redis資料型別介紹

概述 Redis的鍵值可以使用物種資料型別:字串,散列表,列表,集合,有序集合。本文詳細介紹這五種資料型別的使用方法。本文命令介紹部分只是列舉了基本的命令,至於具體的使用示例,可以參考Redis官方文件:Redis命令大全 字串型別 字串是Redis中最基本的資料型別,