系统相关
首页 > 系统相关> > 进程间通信之——有名管道

进程间通信之——有名管道

作者:互联网

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