Linux进程间通信-FIFO(命名管道)
本系列文章主要是学习记录Linux下进程间通信的方式。
常用的进程间通信方式:管道、FIFO、消息队列、信号量以及共享存储。
参考文档:《UNIX环境高级编程(第三版)》
参考视频:Linux进程通信 推荐看看,老师讲得很不错
Linux核心版本:2.6.32-431.el6.x86_64
注:本文档只是简单介绍IPC,更详细的内容请查看参考文档和相应视频。
本文介绍利用FIFO(命名管道)进行进程间的通信。
1 介绍
FIFO也称为命名管道。未命名的管道只能在两个相关的进程之间使用,而且这两个相关进程有一个共同的祖先进程。但是,FIFO可在不相关的进程间交换数据。
本质是内核中的一块缓存,另在文件系统中以一个特殊的设备文件(管道文件)存在。
在文件系统中只有一个索引块存放文件的路径,没有数据块,所有数据存放在内核中。
命令管道必须读和写同时打开,否则单独读或者单独写会引发阻塞。
2 函数原型
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 int mkfifo(const char *pathname, mode_t mode); 4 int mkfifoat(int dirfd, const char *pathname, mode_t mode); 5 说明:创建一个FIFO 6 返回值:成功返回0;出错返回-1。 7 参数[in]:mode参数和open参数相同; 8 参数[in]:pathname文件路径名。 9 参数[in]:dirfd打开目录的有效文件描述符,若pathname是绝对路径名,此参数被忽略;若是相对路径路径名,此参数是一个打开目录的有效文件描述符。
3 操作
创建FIFO时,要用open来打开它。当write一个没有进程为读而打开的FIFO时,会产生信号SIGPIPE;当某个FIFO的最后一个写进程关闭了该FIFO,则将为该FIFO的读进程产生一个文件结束标志。
一旦已经用mkfifo创建了一个FIFO,就可用open打开它,一般的文件I/O函数(close、read、write、unlink等)。
4 测试代码
分别创建一个读和一个写进程,对同一个命令管道进行读写操作。
读进程fifo_read.c:
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 7 int main(int argc, char *argv[]) 8 { 9 if (argc < 2) { 10 printf("usage:%s fifo\n", argv[0]); 11 exit(1); 12 } 13 printf("open fifo read...\n"); 14 int fd = open(argv[1], O_RDONLY); 15 if (fd < 0) { 16 perror("open error"); 17 exit(1); 18 } else { 19 printf("open file success: %d\n", fd); 20 } 21 //从命名管道中读取数据 22 char buf[512] = {0}; 23 while (read(fd, buf, sizeof(buf)) < 0) { 24 perror("read error"); 25 } 26 printf("%s\n", buf); 27 close(fd); 28 29 return 0; 30 }
写进程fifo_write.c:
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <fcntl.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 int main(int argc, char *argv[]) 9 { 10 if (argc < 2) { 11 printf("usage: %s fifo\n", argv[0]); 12 exit(1); 13 } 14 printf("open fifo write...\n"); 15 int fd = open(argv[1], O_WRONLY); 16 if (fd < 0) { 17 perror("open error"); 18 exit(1); 19 } else { 20 printf("open fifo success: %d\n", fd); 21 } 22 char *s = "123456789"; 23 size_t size = strlen(s); 24 if (write(fd, s, size) != size) { 25 perror("write error"); 26 } 27 close(fd); 28 29 return 0; 30 }
测试步骤:
1、先分别编译这两个程序:
[root@192 ipc]# gcc -o bin/fifo_read fifo_read.c
[root@192 ipc]# gcc -o bin/fifo_write fifo_write.c
2、使用mkfifo创建一个命名管道:[root@192 ipc]# mkfifo s.pipe
3、单独只执行其中的一个进程,会阻塞住:
4、另外打开一个终端,执行写进程:
这时读进程也得到了执行:
5 匿名管道和命名管道读写的相同点
(1)默认都是阻塞性读写;
(2)阻塞不完整管道(有一端关闭)
- 单纯读时,在所有数据被读取后,read返回0,以表示到达了文件尾部;
- 单纯写时,则产生信号SIGPIPE,如果忽略该信号或捕捉该信号并从处理程序返回,则write返回-1,同时errno设置为EPIPE。
(3)阻塞完整管道(两端都开启)
- 单纯读时,要么阻塞,要么读取到数据;
- 单纯写时,写到管道满时会出错。
(4)非阻塞不完整管道(有一端关闭)
- 单纯读时直接报错;
- 单纯写时,则产生信号SIGPIPE,如果忽略该信号或捕捉该信号并从处理程序返回,则write返回-1,同时errno设置为EPIPE。
(5)非阻塞完整管道(两端都开启)
- 单纯读时直接报错;
- 单纯写时,写到管道满时会报错。