天天看點

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,建立了一個過濾程式,      主程式給螢幕輸出提示, 我們從螢幕輸入一行字元串,字元串傳給過濾程式,過濾程式處理後發送給主程式,主程式輸出

注意要經常洗刷緩沖區,即把他輸出出來。