程序間的五種通訊方式介紹
程序間通訊(IPC,InterProcess Communication)是指在不同程序之間傳播或交換資訊。
IPC的方式通常有管道(包括無名管道和命名管道)、訊息佇列、訊號量、共享儲存、Socket、Streams等。其中 Socket和Streams支援不同主機上的兩個程序IPC。
以Linux中的C語言程式設計為例。
一、管道
管道,通常指無名管道,是 UNIX 系統IPC最古老的形式。
1、特點:
-
它是半雙工的(即資料只能在一個方向上流動),具有固定的讀端和寫端。
-
它只能用於具有親緣關係的程序之間的通訊(也是父子程序或者兄弟程序之間)。
-
它可以看成是一種特殊的檔案,對於它的讀寫也可以使用普通的read、write 等函式。但是它不是普通的檔案,並不屬於其他任何檔案系統,並且只存在於記憶體中。
一、管道
管道,通常指無名管道,是 UNIX 系統IPC最古老的形式。
1、特點:
-
它是半雙工的(即資料只能在一個方向上流動),具有固定的讀端和寫端。
-
它只能用於具有親緣關係的程序之間的通訊(也是父子程序或者兄弟程序之間)。
-
它可以看成是一種特殊的檔案,對於它的讀寫也可以使用普通的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、特點
-
FIFO可以在無關的程序之間交換資料,與無名管道不同。
-
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、特點
-
訊息佇列是面向記錄的,其中的訊息具有特定的格式以及特定的優先順序。
-
訊息佇列獨立於傳送與接收程序。程序終止時,訊息佇列及其內容並不會被刪除。
-
訊息佇列可以實現訊息的隨機查詢,訊息不一定要以先進先出的次序讀取,也可以按訊息的型別讀取。
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中最基本的資料型別,