天天看点

APUE读书笔记——高级进程通信(管道)

假设我们要将一个文件的数据,通过more程序来显示

但不希望建立临时文件, 即先复制整个文件,再用more来展示

我们可以把文件的数据塞入一个管道,  more程序(由子进程excel启动)读这些数据,并显示在屏幕上

和直接more一个文件有啥区别???

#include "apue.h"
#include <sys/wait.h>
#define DEF_PAGER "/bin/more"
int main(int argc, char *argv[]){
  int n;
  int fd[2];
  pid_t pid;
  char *paper, *argv0;
  char line[MAXLINE];
  FILE *fp;
  if(argc != 2)
    err_quit("usage: a.out <pathname>");
  if((fp = fopen(argv[1], "r")) == NULL)
    err_sys("can't open %s", argv[1]);
  if(pipe(fd) < 0)
    err_sys("pipe error");
  if((pid = fork()) < 0)
    err_sys("pipe error");
  else if(pid > 0){  //parent!
    close(fd[0]);  //关闭读管道端(即管道流向父进程的那段)
    while(fgets(line, MAXLINE, fp) != NULL){
      n = strlen(line);
      //每次读一行,写入管道中
      if(write(fd[1], line ,n) != n)
        err_sys("write error to pipe");
    }
    if(ferror(fp))
      err_sys("fgets error");
    close(fd[1]);
    if(waitpid(pid, NULL, 0) < 0)
      err_sys("waitpid error");
    exit(0);
  }else {
    //子进程,则关闭子进程到管道的那一端
    //故子进程负责读管道
    close(fd[1]);
    if(fd[0] != STDIN_FILENO){
      //重定向,故标准输入成为读管道端
      //从apue画的图上看,描述符0和描述符fd0都指向了管道的读端
      if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO){
        err_sys("dup2 error to stdin");
      }
      //关闭fd0,则此时只有描述符0指向读管道端。
      //即不再是通过fd0与管道联系,而是标准输入与管道联系
      //即不再是fd0读管道,而是子进程的标准输入读管道。
      close(fd[0]);
    }
    if((paper = getenv("PAGER")) == NULL)
      paper = DEF_PAGER;
    if((argv0 = strrchr(paper, '/')) != NULL)
      argv0++;
    else argv0 = paper;
    //启用./bin/more
    //此时,我们可以在终端上输入命令,传给more进程即分页读进程
    execl(paper, argv0, (char *)0);
  }
}      

popen直接将fork和建立单向管道合并在了一起,并且支持缓冲区,即返回文件指针。

这个是大写转小写chengxu

#include "apue.h"
#include <ctype.h>
int main(int argc, char *argv[]){
  int c;
  while( (c = getchar() != EOF)){
    if (isupper(c))
      c = tolower(c);
    if (putchar(c) == EOF)
      err_sys("output error");
    if ( c == '\n')
      fflush(stdout);
  }
  exit(0);
}      
#include "apue.h"
#include <sys/wait.h>
int main(int argc, char *argv[]){
  char line[MAXLINE];
  FILE *fpin;
  
  //fork了一个子进程myuclc,且现在会读子进程的标准输出
  //fpin就是可以读 那个子进程输出 的文件指针
  if((fpin = popen("myuclc", "r")) == NULL)
    err_sys("popen error");
  for(;;){
    fputs("prompt> ", stdout);
    fflush(stdout);  //洗刷标准输出缓冲区,即直接把prompt输出
    //不断读fpin那传来的行
    //那一边每读到一次'\n',就会洗刷缓冲,把一行的内容发送过来
    if(fgets(line, MAXLINE, fpin) == NULL)
      break;
    if(fputs(line, stdout) == EOF)
      err_sys("fputs error to pipe");
  }
  if(pclose(fpin) == -1)
    err_sys("pclose error");
  putchar("\n");
  exit(0);
}      

通过popen,建立了一个过滤程序,      主程序给屏幕输出提示, 我们从屏幕输入一行字符串,字符串传给过滤程序,过滤程序处理后发送给主程序,主程序输出

注意要经常洗刷缓冲区,即把他输出出来。