進程間通訊必須經過內核提供的通道,並且必須有一種辦法在進程中標識內核提供的某個通道,前面講過的匿名管道是用打開的文件描述符來標識的。若是要互相通訊的幾個進程沒有從公共祖先那裏繼承文件描述符,它們怎麼通訊呢?內核提供一條通道不成問題,問題是如何標識這條通道才能使各進程均可以訪問它?文件系統中的路徑名是全局的,各進程均可以訪問,所以能夠用文件系統中的路徑名來標識一個IPC通道。
小程序
FIFO和UNIX Domain Socket這兩種IPC機制都是利用文件系統中的特殊文件來標識的。
socket
FIFO文件在磁盤上沒有數據塊,僅用來標識內核中的一條通道,如 prw-rw-r-- 1 simba simba 0 May 21 10:13 p2,文件類型標識爲p表示FIFO,文件大小爲0。各進程能夠打開這個文件進行read/write,其實是在讀寫內核通道(根本緣由在於這個file結構體所指向的read、write函數和常規文件不同),這樣就實現了進程間通訊。UNIX Domain Socket和FIFO的原理相似,也須要一個特殊的socket文件來標識內核中的通道,例如/run目錄下有不少系統服務的socket文件: 函數
srw-rw-rw- 1 root root 0 May 21 09:59 acpid.socket
測試
.................... spa
文件類型s表示socket,這些文件在磁盤上也沒有數據塊。
.net
1、命名管道(FIFO) 命令行
匿名管道應用的一個限制就是隻能在具備共同祖先(具備親緣關係)的進程間通訊。
若是咱們想在不相關的進程之間交換數據,可使用FIFO文件來作這項工做,它常常被稱爲命名管道。
orm
命名管道能夠從命令行上建立,命令行方法是使用下面這個命令:
$ mkfifo filename
命名管道也能夠從程序裏建立,相關函數有:
int mkfifo(const char *filename,mode_t mode);
blog
2、命名管道和匿名管道 繼承
匿名管道由pipe函數建立並打開。
命名管道由mkfifo函數建立,打開用open。
FIFO(命名管道)與pipe(匿名管道)之間惟一的區別在它們建立與打開的方式不一樣,這些工做完成以後,它們具備相同的語義。
The only difference between pipes and FIFOs is the manner in which they are created and opened. Once these tasks have been accomplished, I/O on pipes and FIFOs has exactly the same semantics.
3、命名管道的打開規則
若是當前打開操做是爲讀而打開FIFO時
O_NONBLOCK disable:阻塞直到有相應進程爲寫而打開該FIFO
O_NONBLOCK enable:馬上返回成功
若是當前打開操做是爲寫而打開FIFO時
O_NONBLOCK disable:阻塞直到有相應進程爲讀而打開該FIFO
O_NONBLOCK enable:馬上返回失敗,錯誤碼爲ENXIO
須要注意的是打開的文件描述符默認是阻塞的,你們能夠寫兩個很簡單的小程序測試一下,主要也就一條語句
int fd = open("p2", O_WRONLY); 假設p2是命名管道文件,把打開標誌換成 O_RDONLY 就是另外一個程序了,能夠先運行RD程序,此時會阻塞,再在另外一個窗口運行WR程序,此時兩個程序都會從open返回成功。非阻塞時也不難測試,open時增長標誌位就能夠了。
須要注意的是 命令管道與匿名管道的讀寫規則是同樣的,參見這裏。
下面示例命名管道完成拷貝文件的功能:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|
/************************************************************************* > File Name: process_.c > Author: Simba > Mail: dameng34@163.com > Created Time: Sat 23 Feb 2013 02:34:02 PM CST ************************************************************************/ #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<signal.h> #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while( 0) int main( int argc, char *argv[]) { mkfifo( "tp", 0644); int infd = open( "Makefile", O_RDONLY); if (infd == - 1) ERR_EXIT( "open error"); int outfd; outfd = open( "tp", O_WRONLY); if (outfd == - 1) ERR_EXIT( "open error"); char buf[ 1024]; int n; while ((n = read(infd, buf, 1024)) > 0) write(outfd, buf, n); close(infd); close(outfd); return 0; } |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|
/************************************************************************* > File Name: process_.c > Author: Simba > Mail: dameng34@163.com > Created Time: Sat 23 Feb 2013 02:34:02 PM CST ************************************************************************/ #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<signal.h> #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while( 0) int main( int argc, char *argv[]) { int outfd = open( "Makefile2", O_WRONLY | O_CREAT | O_TRUNC, 0644); if (outfd == - 1) ERR_EXIT( "open error"); int infd; infd = open( "tp", O_RDONLY); if (infd == - 1) ERR_EXIT( "open error"); char buf[ 1024]; int n; while ((n = read(infd, buf, 1024)) > 0) write(outfd, buf, n); close(infd); close(outfd); unlink( "tp"); // delete a name and possibly the file it refers to return 0; } |