Linux下的管道编程

什么是管道

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

  • 标准输入(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;
}

截图

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值