Linux学习笔记24——进程管道

系统 1421 0

一 管道的作用

  通常把一个进程的输出通过管道连接到另一个进程的输入。

二 popen和pclose函数

      #include <stdio.h>
      
        



FILE 
      
      *popen(
      
        const
      
      
        char
      
       *command,
      
        
          //是要运行的程序名和相应的参数
        
        
       const
char * open_mode      //必须是“r”或者“w”,如果是其它值,errno将返回EINVAL
       );                 
int pclose(FILE *stream_to_close);     

  popen() 函数通过创建一个管道,调用 fork 产生一个子进程,执行一个 shell 以运行命令来开启一个进程。

  pclose()调用只在popen启动的进程结束后才返回,如果调用pclose函数时它仍在运行,pclose调用将等待该进程的结束。

例:

      #include <stdio.h>
      
        

#include 
      
      <stdlib.h>
      
        

#include 
      
      <unistd.h>
      
        

#include 
      
      <
      
        string
      
      .h>




      
        int
      
      
         main(){

    FILE 
      
      *
      
        read_fp;          
        
          //要读取的文件描述符 
        
      
      
        char
      
       buffer[BUFSIZ+
      
        1
      
      
        ];      
        
          //用来存储读到的文件信息 
        
      
      
        int
      
      
         chars_read;          
        
          //实际读取的元素个数
        
        

    

    memset(buffer,
      
      
        '
      
      
        \0
      
      
        '
      
      ,
      
        sizeof
      
      
        (buffer));    
        
          //将数组清零初始化
        
        

    read_fp
      
      =popen(
      
        "
      
      
        cat test*.c | wc -l
      
      
        "
      
      ,
      
        "
      
      
        r
      
      
        "
      
      
        );  
        
          //创建管道,用于显示所有test*.c文件的字数 
        
      
      
        if
      
      (read_fp!=
      
        NULL){

        chars_read
      
      =fread(buffer,
      
        sizeof
      
      (
      
        char
      
      
        ),BUFSIZ,read_fp);
        
          //从一个文件流中读数据,最多读取count个元素,每个元素size字节,如果调用成功返回实际读取到的元素个数,如果不成功返回 0 
        
      
      
        while
      
      (chars_read>
      
        0
      
      
        ){

            buffer[chars_read
      
      -
      
        1
      
      ]=
      
        '
      
      
        \0
      
      
        '
      
      
        ;      
        
          //清除回车符
        
        

            printf(
      
      
        "
      
      
        Reading:-\n %s\n
      
      
        "
      
      
        ,buffer);

            chars_read
      
      =fread(buffer,
      
        sizeof
      
      (
      
        char
      
      
        ),BUFSIZ,read_fp);

        }

        pclose(read_fp);        
        
          //关闭管道
        
        

        exit(EXIT_SUCCESS);

    }

    exit(EXIT_FAILURE);

}
      
    

  使用shell的一个不太好的影响:针对每个popen调用,不仅要启动一个被请求的程序,还要启动一个shell,即每个popen调用将多启动两个进程。从节省系统资源的角度来看,popen函数的调用成本略高,而且对目标命令的调用比正常方式要慢一些。

三 pipe函数

      #include <unistd.h>


      
        int
      
       pipe(
      
        int
      
       fd[
      
        2
      
      ]);
    

  pipe函数的参数是一个由两个整数类型的文件描述符组成的数组的指针,两个返回的文件描述符以一种特殊的方式连接起来,写到fd[1]的所有数据都可以从fd[0]读回来,数据基于先进先出的原则(FIFO)进程处理。

  对一个已关闭写数据的管道做read调用将返回0而不是阻塞,读取无效的文件描述符将看作是一个错误并返回-1
 
  如果跨越fork调用使用管道,就会有两个不同的文件描述符可以用于向管道写数据,一个在父进程中,一个在子进程中。只有把父子进程中的针对管道的写文件描述符都关闭,管道才会被认为是关闭了,对管道的read调用才会失败。

管道的读写规则:

  1 从管道中读取数据

  • 如果管道的写端不存在,则认为已经读到了数据的末尾,读函数返回的读出字节数为0;
  • 当管道的写端存在时,如果请求的字节数目大于PIPE_BUF,则返回管道中现有的数据字节数,如果请求的字节数目不大于 PIPE_BUF,则返回管道中现有数据字节数(此时,管道中数据量小于请求的数据量);或者返回请求的字节数(此时,管道中数据量不小于请求的数据 量)。注:(PIPE_BUF在include/linux/limits.h中定义,不同的内核版本可能会有所不同。Posix.1要求 PIPE_BUF至少为512字节,red hat 7.2中为4096)。

  2 从管道中写入数据

  向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读走管道缓冲区中的数据,那么写操作将一直阻塞。
  注:只有在管道的读端存在时,向管道中写入数据才有意义。否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)。

 

例子:

      #include <stdio.h>
      
        

#include 
      
      <stdlib.h>
      
        

#include 
      
      <unistd.h>
      
        

#include 
      
      <
      
        string
      
      .h>




      
        int
      
      
         main(){

    
      
      
        const
      
      
        char
      
       some_data[]=
      
        "
      
      
        123
      
      
        "
      
      
        ;

    
      
      
        int
      
       file_pipes[
      
        2
      
      
        ];

    
      
      
        int
      
      
         data_processed;

    pid_t fork_result;

    

    
      
      
        if
      
      (pipe(file_pipes)==
      
        0
      
      
        ){

        fork_result
      
      =
      
        fork();

        
      
      
        if
      
      (fork_result==(pid_t)-
      
        1
      
      
        ){

            fprintf(stderr,
      
      
        "
      
      
        Fork failure
      
      
        "
      
      
        );

            exit(EXIT_FAILURE);

        }

        
      
      
        if
      
      (fork_result==
      
        0
      
      
        ){      
        
          //子进程
        
        

            close(
      
      
        0
      
      
        );         
        
           //关闭标准输入,即键盘输入
        
        

            dup(file_pipes[
      
      
        0
      
      
        ]);    
        
          //复制一个文件描述符
        
        

            close(file_pipes[
      
      
        0
      
      
        ]);    
        
          //关闭读操作
        
        

            close(file_pipes[
      
      
        1
      
      
        ]);   
        
          //关闭写操作
        
        

            

            execlp(
      
      
        "
      
      
        od
      
      
        "
      
      ,
      
        "
      
      
        od
      
      
        "
      
      ,
      
        "
      
      
        -c
      
      
        "
      
      ,(
      
        char
      
      *)
      
        0
      
      
        );  
        
          //利用od查看特殊格式的文件内容,-c表示ASCII字符或反斜杠序列,(char*)0参数作用是终止被调用程序的参数列表
        
        

            exit(EXIT_FAILURE);

        }

        
      
      
        else
      
      
        {    
        
           //主进程
        
        

            close(file_pipes[
      
      
        0
      
      
        ]);  

            data_processed
      
      =write(file_pipes[
      
        1
      
      
        ],some_data,strlen(some_data));  
        
          //写入数据
        
        

            close(file_pipes[
      
      
        1
      
      
        ]);

            printf(
      
      
        "
      
      
        %d - wrote %d bytes\n
      
      
        "
      
      
        ,getpid(),data_processed);

        }

    }

    exit(EXIT_SUCCESS);

}
      
    

 

 

 

Linux学习笔记24——进程管道


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论