Linux编程 — IPC之管道

管道,一种古老的进程间通信形式。一个管道由一个进程创建,然后该进程调用fork,此后父、子进程就可以用管道通信了。

函数原型:

#include <unistd.h>
int pipe(int filedes[2]);    // 成功返回0,出错返回-1

参数filedes返回两个文件描述符。filedes[0]用来输入,filedes[1]用来输出。注意,经过实验,这里的两个描述符并不对应标准输入和标准输出。下面是一个简单的测试例程:

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

#define MAXLINE 1024

int main(void)
{
    int n;
    int fd[2];
    pid_t pid;
    char buf[MAXLINE];

    if (pipe(fd) < 0)
        return -1;
    if ((pid = fork()) < 0)
        return -1;
    else if (pid > 0)
    {
        // 父进程
        printf("parent ID = %d\n", getpid());
        close(fd[0]);
        write(fd[1], "Hello world\n", 12);
    }
    else
    {
        // 子进程
        printf("child ID = %d\n", getpid());
        close(fd[1]);
        n = read(fd[0], buf, MAXLINE);
        write(STDOUT_FILENO, buf, n);
    }
    return 0;
}

运行结果:

上述程序利用管道,实现了数据从父进程传递到子进程。数据的传递方向决定了各进程应该关闭的描述符。

现在来看看如何在shell命令中使用管道:

上图使用了管道命令"|"。前一个命令的输出作为了后一个命令的输入。注意,这里的输出只能是标准输出,输入也只能是标准输入,也就是说前一个命令必须要有输出到标准输出的能力,后一个命令必须要有接受标准输入的能力。下图来自鸟哥的网站。

下面用一个程序来模拟上述shell命令的行为。一种常见的操作时创建一个管道连接到另一个进程,然后读其输出或向其输入发送数据。这是可以使用下列两个库函数:

#include <stdio.h>
FILE *popen(const char *cmdstring, const char *type);    // 成功返回文件指针,出错返回NULL
int pclose(FILE *fp);    // 获得cmdstring的终止状态,出错返回-1

popen等价于fork、exec("cmdstring")启动一个子进程。type的含义如下:

  • "r"表示文件指针连接到cmdstring的标准输出,父进程读cmdstring的数据。
  • "w"表示文件指针连接到cmdstring的标准输入,父进程向cmdstring写数据。

有几个问题需要注意:

  • popen返回的文件指针同样不对应标准输入和标准输出,这可以通过fileno函数把文件指针转换成文件描述符进行查看。
  • 函数pclose不仅关闭标准I/O流,还要获得子进程终止状态。如果不使用这个函数,当父进程还在运行而子进程运行完毕后会产生僵死进程,等下会通过实验来说明。

测试例程如下:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define MAXLINE 1024

int main(void)
{
    char buf[MAXLINE];
    FILE *fpin;
    int n;

    if ((fpin = popen("date", "r")) == NULL)  // 启动data命令
        return -1;

    fgets(buf, MAXLINE, fpin);                    // 获得data命令的输出
    write(STDOUT_FILENO, buf, strlen(buf));       // 将数据打印到终端
    pclose(fpin);

    return 0;
}

运行结果:

父进程test正确地接收了data命令的输出,管道传输成功。如果去掉pclose(fpin);这条语句,那么结果如下:

啊哦,出现一个僵死进程。这就是因为父进程没有获得子进程的终止状态而引起的。

参考:

《unix环境高级编程》 P397-P404.

Linux编程 — IPC之管道

时间: 2024-12-28 19:00:29

Linux编程 — IPC之管道的相关文章

linux应用开发-无名管道编程

linux应用开发-无名管道编程 一 linux进程间通信(ipc) 1 UNIX进程间通信 2 基于System V的通信 3 POSIX通信 二 七种通信方式 1 管道 一个进程在管道的尾部写入数据,另一个进程从管道的头部 读出数据.管道包括无名管道和有名管道两种,前者只能用 于父进程和子进程间的通信,后者可用于运行于同一系统中 的任意两个进程间的通信. 分类: 无名管道(pipo):用于父进程和子进程间的通信 有名管道(FIFO):用于运行于同一系统中的任意两个进程间的通信 特点: 1 管

【Linux编程】XSI IPC

三种IPC被称作XSI IPC,分别是: 消息队列 信号量 共享存储器 下面分别介绍三种IPC的用法. 1.消息队列 消息队列是消息的链接表,具有如下函数接口: msgget:创建一个新队列或打开一个现存的队列. msgsnd:将消息添加到队列尾端. msgrcv:从队列中取消息. 我们可以自行定义一个表示消息的结构体,它由类型字段和实际数据组成: struct mest_t { long type; // 消息类型 char text[512]; // 消息内容 }; 有了消息类型,当我们用m

linux应用开发-有名管道编程

linux应用开发-有名管道编程 一 有名管道 用于任意两个进程通信,有名管道又称为FIFO文件,因此我们对有名管 道的操作可以采用操作文件的方法,如使用open,read,write等. 2 特点 FIFO文件在使用上和普通文件有相似之处,但是也有不同之处: 1. 读取Fifo文件的进程只能以"RDONLY"方式打开fifo文件. 2. 写Fifo文件的进程只能以"WRONLY"方式打开fifo 3. Fifo文件里面的内容被读取后,就消失了.但是普通文件里面的内

I/O重定向和管道——《Unix/Linux编程实践教程》读书笔记(第10章)

1.I/O重定向的概念与原因 及 标准输入.输出的标准错误的定义 所以的Unix I/O重定向都基于标准数据流的原理.三个数据了分别如下: 1)标准输入--需要处理的数据流 2)标准输出--结果数据流 3)标准错误输出--错误消息流 概念:所以的Unix工具都使用文件描述符0.1和2.标准输入文件的描述符是0,标准输出的文件描述符是1,而标准错误输出的文件描述符则是2.Unix假设文件描述符0.1.2已经被打开,可以分别进行读写操作. 通常通过shell命令行运行Unix系统工具时,stdin.

linux各种IPC机制(进程通信)

linux各种IPC机制 (2011-07-08 16:58:35)     原文地址:linux各种IPC机制(转)作者:jianpengliu 原帖发表在IBM的developerworks网站上,是一个系列的文章,作者郑彦兴,通过讲解和例子演示了Linux中几种IPC的使用方式,我觉得很好,在这里做一个保留,能看完的话Linux IPC的基础是没有问题的了.一)Linux环境进程间通信(一)管道及有名管道http://www.ibm.com/developerworks/cn/linux/

Linux编程---进程通信

Linux的通信方式主要有分类有下面几种: -匿名管道和FIFO有名管道 -消息队列,信号量和共享存储 -套接字 .对于套接字的进程通信,我就留在套接字的文章中再写了. 一.管道 管道是最古老的进程通信机制了.提供进程间的单向通信. 1.创建管道 int pipe(int fdes[2]); 实际上管道通过参数返回读和写的两个文件描述符.相当于是打开了两个文件吧.但是这个文件是特殊的pipe文件.fdes[0]表示的是输入,fdes[2]表示的是输出.注意,这个函数只创建一个文件,而不是创建两个

Linux编程---I/O部分

非常多函数都能够在网上找到,也比較基础,所以原型仅仅给出了函数名.详细用到再man吧. 输入输出是个非常重要的一块内容.差点儿网络相关的东西基本都是靠底层IO调用来实现的. 好吧.还是先踏踏实实的介绍一下C标准库中的IO函数吧.个别函数我也是第一次见.对于不太常见的我就多解释一下,反正通常这些函数百度一下就清楚了,我就不多解释了~ 1.C标准库IO函数 1.1流的关闭开启与重定向 fopen:打开一个流 fclose:关闭一个流 freopen:又一次打开一个流 1.2 读与写 读: fgetc

linux编程中接收主函数返回值以及错误码提示

程序A创建子进程,并调用进程B,根据不调用的不同情况,最后显示结果不同. #include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h> #include <errno.h> int main() { pid_t pid, rpid; int stat; if ((pid = fork()) < 0) { perror("for

笔记整理--Linux编程

linux c编程open() read() write()函数的使用方法及实例 | 奶牛博客 - Google Chrome (2013/8/31 17:56:10) 今天把文件IO操作的一些东东整理下.基本的,对于锁机制下次再整理.常用的文件IO函数有标题的三个open() read() write() .首先打开一个文件使用open()函数,然后可以获取到一个文件描述符,这个就是程序中调用这个打开文件的一个链接,当函数要求到文件描述符fd的时候就把这个返回值给函数即可.read跟write