进程间通信之——有名管道
作者:互联网
1、概述
无名管道只能在具有亲缘关系的进程中使用,而有名管道可以在互不相关的两个进程间使用。有名管道将管道以文件的方式存储在指定路径中,使用ls -l可以看到第一个字符是‘p’,表示这是一个管道文件。文件操作用标准IO,即open,read,write,close。
2、函数介绍
2.1 创建管道文件
2.2.1 mkfifo
函数原型 | int mkfifo(const char *pathname, mode_t mode); |
头文件 | sys/types.h、sys/stat.h |
功能 | 创建一个管道文件 |
参数 |
[in]:pathname:文件路径 [in]:mode:文件权限 |
返回 | 成功返回0,失败返回-1 |
与有名信号量不同,管道文件是可以自己指定路径的。文件的权限也是与掩码相关的,(mode & (~umask))才是真正的文件权限,umask的值可以在终端直接输入umask查看。使用mkfifo创建的文件必须是不存在的,否则会出错,并置errno为EEXIST,此外还有其他错误码,可以通过在终端输入man 3 mkfifo查看。
3、测试程序
fifo1.c
1 /** 2 * filename: fifo1.c 3 * author: Suzkfly 4 * date: 2021-02-10 5 * platform: Ubuntu 6 * 配合fifo2使用,在一个终端执行fifo1,输入数据,按回车结束,另开1个终端执行 7 * fifo2,从fifo1中输入的数据能从fifo2中读出来。 8 */ 9 #include <stdio.h> 10 #include <fcntl.h> 11 #include <sys/types.h> 12 #include <sys/stat.h> 13 #include <string.h> 14 15 int main(int argc, const char *argv[]) 16 { 17 int ret = 0; 18 int fd = 0; 19 char buf[128] = { 0 }; 20 21 /* 创建fifo文件 */ 22 #if 1 23 ret = mkfifo("myfifo", 0666); 24 if (ret == -1) { 25 printf("mkfifo failed\n"); 26 return 0; 27 } 28 printf("ret = %d\n", ret); 29 #endif 30 31 /* 以只写方式打开fifo文件 */ 32 fd = open("myfifo", O_WRONLY); 33 while (1) { 34 memset(buf, 0, sizeof(buf)); 35 scanf("%s", buf); 36 ret = write(fd, buf, strlen(buf)); 37 printf("write ret = %d\n", ret); 38 } 39 40 close(fd); 41 42 return 0; 43 }
fifo2.c
1 /** 2 * filename: fifo2.c 3 * author: Suzkfly 4 * date: 2021-02-10 5 * platform: Ubuntu 6 * 配合fifo1使用,在一个终端执行fifo1,输入数据,按回车结束,另开1个终端执行 7 * fifo2,从fifo1中输入的数据能从fifo2中读出来。 8 */ 9 #include <stdio.h> 10 #include <fcntl.h> 11 #include <sys/types.h> 12 #include <sys/stat.h> 13 #include <string.h> 14 15 int main(int argc, const char *argv[]) 16 { 17 int ret = 0; 18 int fd = 0; 19 char buf[128] = { 0 }; 20 21 /* 打开fifo文件,以只读方式打开 */ 22 fd = open("myfifo", O_RDONLY); 23 while (1) { 24 memset(buf, 0, sizeof(buf)); 25 ret = read(fd, buf, sizeof(buf)); 26 printf("read ret = %d\n", ret); 27 printf("read data:%s\n", buf); 28 } 29 30 close(fd); 31 32 return 0; 33 }
测试结果:
代码分析:
测试例程代码比较简单,fifo1用来写数据,fifo2用来读数据,执行程序时需要先执行fifo1再执行fifo2,在fifo1的终端中输入数据,以回车键结束,在fifo2的终端中可以打印数据。
4、注意事项
1. 如果一个进程以只写方式打开管道文件,如果没有其他进程以带有读的方式(只读/读写)打开管道文件,那么写数据的操作将会阻塞,直到管道文件以被带有读的方式打开。(写阻塞不是因为没有读数据,而是没有以带有读的方式打开管道文件)。但是如果有进程以带读的方式打开了管道文件,之后又将文件关闭了,此时写端再向管道写数据则会收到SIGPIPE(管道破裂)信号,默认情况下写数据的进程会直接退出。
2. 如果一个进程以只读方式打开管道文件,如果没有其他进程以带有写的方式(只写/读写)打开管道文件,并且往管道内写数据,那么读操作将会阻塞。但是如果有进程以带写的方式打开了管道文件,之后又将文件关闭了,此时读端再向管道读数据则会收到SIGPIPE(管道破裂)信号,默认情况下写数据的进程会直接退出。
3. 如果一个进程以读写方式打开管道文件,那么即使没有其他进程以带有读的方式打开管道文件,它往管道写数据的操作也不会阻塞,并且可以自己将数据读出来。
上面3条我总结一下,一个有名管道存在一个类似于建立连接的机制,有写无读时写阻塞,有读无写或未写时读阻塞,但一旦建立好连接,之后如果所有的写端关闭,那么读操作会导致管道破裂,如果所有的读端关闭,那么写操作会导致管道破裂。
标签:文件,fifo2,fifo1,ret,间通信,管道,有名,buf 来源: https://www.cnblogs.com/Suzkfly/p/14396903.html