IPC - 管道(pipe) - 应用

关于IPC

IPC,即Inter-Process Communication(进程间通信)。
我们都知道,进程一段程序的执行过程,是系统进程资源分配和调度的基本单位

那么为什么要引入进程间通信呢?或者说,进程间通信能带来哪些好处?

为什么需要IPC?

  • 数据传输
  • 共享数据
  • 通知事件
  • 资源共享
  • 进程控制

上面几点都很好理解,我们可以着重看一下最后一点:进程控制
有一些进程希望能够完全控制另一个进程的执行(比如Debug进程),此时控制进程希望能够拦截到另一进程的所有异常,并能够及时知道它的状态改变。

这一点,相信编程过的大家都很有体会吧,我们在写完一段代码,调试程序的时候,打断点分步执行进入执行跳出执行等等,每执行一步,我们可以通过监视器、或者查看内存中的数据来检查程序是否按照我们预想的那样执行,从而发现错误,修正错误。
如果没有进程间通信的话,进程与进程之间你执行你的,我执行我的,井水不犯河水,那么,如何实现调试的功能呢?

IPC的方法?

  1. 无名管道(pipe)
  2. 有名管道(fifo)
  3. 共享内存
  4. 消息队列
  5. 信号量
  6. Socket

今天介绍的重点就是无名管道pipe

关于管道

我们都知道每个进程都有自己的4G虚拟地址空间在这里插入图片描述
对于每个进程来说,3G的用户空间是独有的,1G的内核空间是共享的
基于此,管道本质上就是内核空间中的一块缓存

对于无名管道而言:

  • 必须在关系进程中进程(父子进程或兄弟进程);
  • pipe系统调用,管道由父进程建立;

函数原型:

#include <unistd.h>
int pipe(int fields[2])

其中的fields是我们传入的数组,也是一个传出参数。
fields[0]读端
fields[1]写端

对于命名管道而言:

  • 没有任何关系的进程间也可以通信;
  • 通过mkfifo系统调用创建。

关于 " | "

在Linux系统中," | " 就代表了管道。
比如说我们想通过查看Linux系统中的用户信息:
cat /etc/passwd
在这里插入图片描述
我们会看到非常多的信息。
此时,我只想看root用户的信息,该怎么做呢?
cat /etc/passwd | grep root
在这里插入图片描述
对于该命令的解读是:
在这里插入图片描述

pipe实现 " | "

通过对上面命令的解读,我们会发现,需要两个子进程,分别做catgrep的工作,然后将cat的执行结果写入管道,grep从管道中读取内容并且过滤

注意:
我们通过前面命令可以看到:cat的执行结果是默认输出到屏幕(标准输出)的,而grep的默认读取也是标准输入
所以,我们为了实现通信,需要将标准输入和标准输出进行重定向(使用dup2())。

代码如下:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <wait.h>

char *cmd1[3] = {"/bin/cat", "/etc/passwd", NULL};
char *cmd2[3] = {"/bin/grep", "root", NULL};

int main()
{
    int fd[2];
    if (pipe(fd) < 0)
    {
        perror("pipe error");
        exit(1);
    }
    int i = 0;
    pid_t pid;
    for (; i < 2; i++)
    {
        pid = fork();
        if (pid < 0)
        {
            perror("fork error");
            exit(1);
        }
        else if (pid == 0) // child process
        {
            if (i == 0) // 第一个子进程,负责向管道写入数据
            {
                // 关闭读端
                close(fd[0]);

                // 将标准输出重定向到管道的写端
                // 下面命令执行的结果会写入到管道中
                // 而不是输出到屏幕
                if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
                {
                    perror("dup2 error");
                }
                close(fd[1]);

                // 调用exec函数执行cat命令
                if (execvp(cmd1[0], cmd1) < 0)
                {
                    perror("execvp error");
                    exit(1);
                }
                break;
            }
            if (i == 1) // 第二个子进程,负责从管道读取数据
            {
                // 关闭写端
                close(fd[1]);

                /*
                 * 将标准输入重定向到管道的读端
                 * 下面命令grep的执行是从管道的读端
                 * 读取内容,而不是从标准输入读取
                 */
                if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
                {
                    perror("dup2 error");
                    exit(1);
                }
                close(fd[0]);

                // 调用exec函数执行grep命令
                if (execvp(cmd2[0], cmd2) < 0)
                {
                    perror("execvp error");
                    exit(1);
                }
                break;
            }
        }
        else // parent process
        {
            if (i == 1)
            {
                // 父进程要等到子进程全部创建完毕才会去回收
                close(fd[0]);
                close(fd[1]);
                wait(0);
                wait(0);
            }
        }
    }

    exit(0);
}

运行结果对比:
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值