进程间通讯必须经过内核提供的通道,并且必须有一种办法在进程中标识内核提供的某个通道,前面讲过的匿名管道是用打开的文件描述符来标识的。若是要互相通讯的几个进程没有从公共祖先那里继承文件描述符,它们怎么通讯呢?内核提供一条通道不成问题,问题是如何标识这条通道才能使各进程均可以访问它?文件系统中的路径名是全局的,各进程均可以访问,所以能够用文件系统中的路径名来标识一个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; } |