Linux環境下,程序位址空間互相獨立,每個程序各自有不同的使用者位址空間。任何一個程序的全局變量在另一個程序中都看不到,是以程序和程序之間不能互相通路,要交換資料必須通過核心,在核心中開辟一塊緩沖區,程序1把資料從使用者空間拷到核心緩沖區,程序2再從核心緩沖區把資料讀走,核心提供的這種機制稱為程序間通信(IPC,InterProcess Communication)。
在程序間完成資料傳遞需要借助作業系統提供特殊的方法,如:檔案、管道、信号、共享記憶體、消息隊列、套接字、命名管道等。随着計算機的蓬勃發展,一些方法由于自身設計缺陷被淘汰或者棄用。現今常用的程序間通信方式有:
① 管道 (使用最簡單)
② 信号 (開銷最小)
③ 共享映射區 (無血緣關系)
④ 本地套接字 (最穩定)
管道
未名管道(匿名管道)
管道是一種最基本的IPC機制,作用于有血緣關系的程序之間,完成資料傳遞。調用pipe系統函數即可建立一個管道。有如下特質:
1. 其本質是一個僞檔案(實為核心緩沖區)
linux檔案類型:- 檔案 d 目錄 l 符号連結
s 套接字 b塊裝置 c 字元裝置 p 管道 (這四種都是僞檔案)
- 由兩個檔案描述符引用,一個表示讀端,一個表示寫端。
-
規定資料從管道的寫端流入管道,從讀端流出。
管道的原理: 管道實為核心使用環形隊列機制,借助核心緩沖區(4k)實作。
管道的局限性:
① 資料自己讀不能自己寫。
② 資料一旦被讀走,便不在管道中存在,不可反複讀取。
③ 由于管道采用半雙工通信方式。是以,資料隻能在一個方向上流動。
④ 隻能在有公共祖先的程序間使用管道。(有血緣關系的程序)
常見的通信方式有,單工通信、半雙工通信、全雙工通信。
pipe函數
建立管道
int pipe(int pipefd[2]); 成功:0;失敗:-1,設定errno
函數調用成功傳回r/w兩個檔案描述符。無需open,但需手動close。規定:fd[0] → r; fd[1] → w,就像0對應标準輸入,1對應标準輸出一樣。向管道檔案讀寫資料其實是在讀寫核心緩沖區。
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main()
{
int fd[2];
int ret =0;
ret = pipe(fd);
pid_t pid;
if(ret == -1)
{
perror("pipe error.\n")
exit(1);
}
pid = fork();
if(pid == -1)
{
perror("fork error.\n");
exit(1);
}
else if(pid ==0)
{
close(fd[1]);//子程序負責讀,是以關閉寫的描述符
char buf[1024];
ret = read(fd[0],buf,sizeof(buf));//從管道讀資料
if(ret == 0)
{
printf("end.\n");
}
write(STDOUT_FILENO,buf,ret);//寫到螢幕
}
else
{
close(fd[0]);//父程序負責寫,是以關閉讀的描述符
char *str ="hello ,pipe.";
write(fd[1],str,strlen(str));
}
return 0;
}
FIFO
命名管道
FIFO常被稱為命名管道,以區分管道(pipe)。管道(pipe)隻能用于“有血緣關系”的程序間。但通過FIFO,不相關的程序也能交換資料。
FIFO是Linux基礎檔案類型中的一種。但,FIFO檔案在磁盤上沒有資料塊,僅僅用來辨別核心中一條通道。各程序可以打開這個檔案進行read/write,實際上是在讀寫核心通道,這樣就實作了程序間通信。
建立方式:
1. 指令:mkfifo 管道名
2. 庫函數:int mkfifo(const char *pathname, mode_t mode); 成功:0; 失敗:-1
一旦使用mkfifo建立了一個FIFO,就可以使用open打開它,常見的檔案I/O函數都可用于fifo。如:close、read、write、unlink等。
有名管道的打開規則:
有名管道比無名管道多了一個打開操作:open
FIFO的打開及讀寫規則:
一、對于FIFO,需要open去打開FIFO的讀端或是寫端的描述符。
1> 如果open的時候沒有指定O_NONBLOCK标志,且open的是讀端時
如果不存在此FIFO的已經打開的寫端時,open會一直阻塞到有FIFO的寫端打開;
如果已經存在此FIFO的打開的寫端時,open會直接成功傳回。
2> 如果open的時候沒有指定O_NONBLOCK标志,且open的是寫端時
如果不存在此FIFO的已經打開的讀端時,open會一直阻塞到有FIFO的讀端打開;
如果已經存在此FIFO的打開的讀端時,open會直接成功傳回。
二、從FIFO或者空管道讀寫
1> read時,讀端fd沒有指定O_NONBLOCK标志
如果存在此FIFO或管道的已經打開的寫端時,阻塞到FIFO或管道中有資料或者FIFO或管道的已經打開的寫端全部被關閉為止。
如果不存在此FIFO或管道的已經打開的寫端時,read傳回0;
2> write時, 同read差不多,就不詳述了。