首页 > 系统服务 > 详细

Linux进程间通信-管道(pipe)

时间:2020-06-01 22:30:33      阅读:52      评论:0      收藏:0      [点我收藏+]

本系列文章主要是学习记录Linux下进程间通信的方式。

常用的进程间通信方式:管道、FIFO、消息队列、信号量以及共享存储。

参考文档:《UNIX环境高级编程(第三版)》

参考视频:Linux进程通信  推荐看看,老师讲得很不错

Linux核心版本:2.6.32-431.el6.x86_64

注:本文档只是简单介绍IPC,更详细的内容请查看参考文档和相应视频。

本文介绍利用管道进行进程间的通信。

1  简介

管道是最古老的一种方式,局限性:

  • 半双工方式,数据只能在一个方向上流动;
  • 只能在具有公共祖先的两个进程间使用。

2  函数接口

1 #include <unistd.h>
2 int pipe(int pipefd[2]);
3 说明:常见一个pipe
4 返回值:成功返回0,出错返回-1
5 参数[out]:fd保存返回的两个文件描述符,fd[0]为读而打开,fd[1]为写而打开。fd[1]的输出是fd[0]的输入。

3  通信模型

通信模型一:进程先调用pipe,接着调用fork,从而创建从父进程到子进程的IPC通道。

技术分享图片

通信模型二:从父进程到子进程的通道。父进程关闭管道的读端(fd[0]),子进程关闭写端(fd[1])。

 技术分享图片

当管道一端被关闭后,以下两条规则起作用:

当读(read)一个写端已被关闭的管道时,在所有数据都被读取后,read返回0,表示文件结束。

如果写(write)一个读端已被关闭的管道,则产生信号SIGPIPE。

 4  测试代码

 (1)案例1

创建一个从父进程到子进程的管道,并且父进程通过该管道向子进程传送数据。

技术分享图片
 1 #include <stdio.h>
 2 #include <unistd.h>
 3 
 4 #define MAXLINE 512
 5 
 6 int main(void)
 7 {
 8     int n;
 9     int fd[2];
10     pid_t pid;
11     char line[MAXLINE];
12 
13     if (pipe(fd) < 0) {  //创建管道
14         perror("pipe error!");
15         return -1;
16     }
17     if ((pid = fork()) < 0) {  //创建子进程
18         perror("fork error!");
19         return -1;
20     } else if (pid > 0) {  //父进程
21         close(fd[0]);    //父进程关闭读管道
22         write(fd[1], "hello world\n", 12);  //父进程向管道中写入数据
23         close(fd[1]);
24         wait(0);  //等待子进程结束
25     } else {  //子进程
26         close(fd[1]);  //子进程关闭写管道
27         n = read(fd[0], line, MAXLINE);  //子进程从管道中读取数据
28         write(STDOUT_FILENO, line, n);   //标准输出
29         close(fd[0]);
30     }
31 
32     return 0;
33 }
View Code

(2)案例2

使用pipe实现类似于:cat /etc/passwd | grep root这个命令。

技术分享图片

技术分享图片
 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <stdlib.h>
 4 
 5 char *cmd1[3] = {"/bin/cat", "/etc/passwd", NULL};
 6 char *cmd2[3] = {"/bin/grep", "root", NULL};
 7 
 8 int main(void)
 9 {
10     int fd[2];
11     int i = 0;
12     pid_t pid;
13 
14     if (pipe(fd) < 0) {
15         perror("pipe error");
16         exit(1);
17     }
18 
19     for (i = 0; i < 2; i++) {
20         pid = fork();
21         if (pid < 0) {
22             perror("fork error");
23             exit(1);
24         } else if (pid == 0) {
25             if (i == 0) {  //第一个子进程
26                 //负责往管道写入数据
27                 close(fd[0]);  //关闭读端
28                 //cat命令执行结果是标准输出,需要将标准输出重定向到管道写端
29                 //下面命令执行的结果会写入到管道中,而不是输出到屏幕
30                 if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
31                     perror("dup2 error");
32                     exit(1);
33                 }
34                 close(fd[1]);  //已经复制了一份,原来的可以关闭
35                 //调用exce函数执行cat命令
36                 if (execvp(cmd1[0], cmd1) < 0) {
37                     perror("execvp error");
38                     exit(1);
39                 }
40                 break;
41             }
42             if (i == 1) {  //第二个子进程
43                 //负责从管道读取数据
44                 close(fd[1]);  //关闭写端
45                 //grep命令默认读取的内容来源于标准输入
46                 //需要将标准输入重定向到管道的读端
47                 //下面命令执行时从管道的读端读取内容,而不是从标准输入读取
48                 if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
49                     perror("dup2 error");
50                     exit(1);
51                 }
52                 close(fd[0]);
53                 //调用exce函数执行grep命令
54                 if (execvp(cmd2[0], cmd2) < 0) {
55                     perror("execvp error");
56                     exit(1);
57                 }
58                 break;
59             }
60         } else {  //父进程,仅用于创建子进程
61             //等待子进程创建并回收
62             if (i == 1) {
63                 //等待子进程全部创建完毕,才回收
64                 close(fd[0]);
65                 close(fd[1]);
66                 wait(0);
67                 wait(0);
68             }
69         }
70     }
71 
72     return 0;
73 }
View Code

Linux进程间通信-管道(pipe)

原文:https://www.cnblogs.com/mrlayfolk/p/13027545.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!