Linux下的管道编程

来源:互联网 发布:阿里云cdn节点ip 编辑:程序博客网 时间:2024/06/05 04:59

什么是管道

管道是内核中一个单向的数据通道,有一个读取端和一个写入端,可以连接两个进程。
进程有三个标准数据流:

  • 标准输入(stdin),文件描述符0
  • 标准输出(stdout),文件描述符1
  • 标准错误输出(stderr),文件描述符2

管道将一个进程的输出和另一个进程的输入连接起来,数据便可以从一个进程传递到另一个进程。

pipe函数

可以用pipe函数来创建管道
头文件:#include <unistd.h>
函数原型:result = pipe(int array[2])
参数:array[0]为从管道读取数据端的文件描述符
   array[1]为写入管道数据端的文件描述符
   他们是输出参数。
返回值:-1代表错误,0代表成功
pipe调用
使用最低可用文件描述符。一般情况下,0,1,2被标准
数据流占用,所以array[0],array[1],分别是3,4.

下面的程序展示了如何创建管道,并用管道向自己发送数据

数据流向是这样的
这里写图片描述

#include <stdio.h>#include <unistd.h>int main(){    int len,i,apipe[2];    char buf[BUFSIZ];    /*get a pipe*/    if(pipe(apipe) == -1)    {        perror("Could not make pipe");        exit(1);    }    printf("Got a pipe! It's file descriptors: { %d %d}\n",apipe[0],apipe[1]);    /*read from stdin, write into pipe, read from pipe, print*/    while(fgets(buf,BUFSIZ,stdin))    {        len=strlen(buf);        /*将buf写入进管道*/        if( write( apipe[1],buf,len) != len)        {            perror("writing to pipe");            break;        }        /*将原来的buf数组清空*/        for(i=0; i<len; i++)            buf[i]='X';        /*从管道中读取数据放在buf中*/        len = read(apipe[0],buf,BUFSIZ);        if( len == -1)        {            perror("reading from pipe");            break;        }        /*将buf中的数据写到标准输出(文件描述符为1)中*/        if( write(1,buf,len) != len)        {            perror("writing to stdout");            break;        }    }    return 0;}

相关函数:
write
目标:将函数中的数据写入文件
头文件:#include <unistd.h>
函数原型:ssize_t result = write(int fd, void* buf, size_t amt);
参数:fd是文件描述符
   buf是内存数据
   amt是要写的字节数
返回值:成功则返回写入的字节数,失败返回-1
注:有些情况写入成功,但写入的字节数并不等于要写的字节数,比如磁盘空间不足等,所以要检查。result是否等于amt

read
目标:把数据读入缓冲区
头文件:#include <unistd.h>
函数原型:ssize_t numread = read(int fd, void* buf, size_t qty);
参数:fd是文件描述符
   buf是存放数据的缓冲区
   qty是要读取的字节数
返回值:成功则返回读取的字节数,失败返回-1
注:有些情况读取成功,但读取的字节数不一定等于要读的字节数,比如文件里没那么多数据

截图

这里写图片描述

当然,很少有进程会用管道给自己发送数据

下面的程序展示了如何用fork函数实现两个进程共享一个管道

当进程创建了一个管道后,该进程就又连向管道两端的连接。当调用fork函数后,子进程也得到了这个连接。这时父进程和子进程都可以读写这个管道
这里写图片描述

#include <stdio.h>#define CHILD_MESS  "I want a cookie\n"#define PAR_MESS    "testing...\n"#define oops(m,x)   {perror(m);exit(x);}int main(){    int pipefd[2];    int len;    char buf[BUFSIZ];    int read_len;    /*建立一个管道*/    if( pipe( pipefd ) == -1)        oops("cannot get a pipe", 1);    /*这个switch很巧妙啊,复制一个进程,然后判断父进程还是子进程*/    /*这里的switch里没有break,虽然这个程序不会用到break,但我觉得还是写上比较好*/    switch( fork() ){        case -1:            oops("cannot fork", 2);    /*child writes to pipe every 5 seconds*/    case 0:        len = strlen(CHILD_MESS);        while(1){            /*将GHILD_MESS写入管道*/                         if(write( pipefd[1], CHILD_MESS,len) != len )                oops("write",3);            sleep(5);        }    /*parent reads from pipe and also write to pipe*/    default:       len = strlen(PAR_MESS);       while(1){           if( write( pipefd[1], PAR_MESS, len) != len)               oops("write",4);           sleep(1);           read_len = read( pipefd[0], buf, BUFSIZ);           if( read_len <= 0)               break;           write(1, buf, read_len);        /*将buf写到标准输出中*/       }    }    return 0;}

截图

这里写图片描述

0 0