管道与FIFO的区别,就在于 unnamed 和 named 的区别:
#include <unistd.h> int pipe (int fd[2]); /* Return value: if success, return 0; if error, return -1 */int fd[2],顾名思义,file descriptors,是两个文件描述符fd[0]和fd[1];
#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 *pager, *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]); /* create a pipe */ if(pipe(fd) < 0) err_sys("pipe error"); /* fork */ if((pid = fork()) < 0) err_sys("fork error"); else if(pid > 0) { close(fd[0]); /* parent process close read end */ /* parent read argv[1] and write to pipe */ 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]); /* close write end of pipe for reader */ /* wait until the child process terminate, if not wait, system will not release the resources associated with the child, and the child of course will become a "zombie". */ if(waitpid(pid, NULL, 0) < 0) err_sys("waitpid error"); exit(0); } else { close(fd[1]); /* child process close write end */ /* duplicate the read end to STDIN_FILENO */ if(fd[0] != STDIN_FILENO) { /* duplicate from the old fd to new fd */ if(dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) err_sys("dup2 error to stdin"); close(fd[0]); /* we don't need this after dup2 */ } /* From this section, we can see how to use the "environ" to call the page program. */ /* get arguments for execl() */ if((pager = getenv("PAGER")) == NULL) pager = DEF_PAGER; if((argv0 = strrchr(pager, '/')) != NULL) argv0++; /* step past rightmost slash */ else argv0 = pager; /* no slash in pager */ if(execl(pager, argv0, (char *)0) < 0) err_sys("execl error for %s", pager); } exit(0); }程序很长,但无论怎样应该好好看看。
#include <stdio.h> FILE *popen(const char *cmdstring, const char *type); /* Returns: file pointer if OK, NULL on error */ int pclose(FILE *fp); /* Returns: termination status of cmdstring, or −1 on error */(1)popen函数
/* This is a filter program that transform upper characters to the lowers */ #include "apue.h" #include <ctype.h> int main(void) { 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); }
/* This is the program that calls popen */ #include "apue.h" #include <sys/wait.h> int main(void) { char line[MAXLINE]; FILE *fpin; /* call popen function to create a pipe and execute filter program */ if((fpin = popen("./filter", "r")) == NULL) err_sys("popen error"); for(; ;) { fputs("prompt> ", stdout); fflush(stdout); if(fgets(line, MAXLINE, fpin) == NULL) /* read from pipe */ break; if(fputs(line, stdout) == EOF) err_sys("fputs error to pipe"); } /* close the pipe */ if(pclose(fpin) == -1) err_sys("pclose error"); putchar('\n'); exit(0); }程序运行时,将输入的大写转换为小写,遇到EOF(ctrl+D)时结束。
#include "apue.h" int main(void) { int n, int1, int2; char line[MAXLINE]; while ((n = read(STDIN_FILENO, line, MAXLINE)) > 0) /* read from STDIN_FILENO */ { line[n] = 0; /* note: null terminate */ if(sscanf(line, "%d%d", &int1, &int2) == 2) /* read int1, int2 from line[MAXLINE] */ { sprintf(line, "%d\n", int1 + int2); /* write sum of int1 and int2 to line[MAXLINE] */ n = strlen(line); if(write(STDOUT_FILENO, line, n) != n) /* write line[MAXLINE] to STDOUT_FILENO */ err_sys("write error"); } else { if(write(STDOUT_FILENO, "invalid args\n", 13) != 13) err_sys("write error"); } } }上面的程序中,read后的line[n]=0需要注意,其余4种读写的方式了解一下;
/* fifo.h */ #include <stdlib.h> #include <stdio.h> #include <sys/stat.h> /* FIFO is a type of file; this header includes mkfifo function */ #include <fcntl.h> #include <errno.h> //#include <unistd.h> #define FIFO1 "/tmp/fifo.1" #define FIFO2 "/tmp/fifo.2" #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
/* server.c */ #include "fifo.h" void server(int readfd, int writefd) { /* ... */ } int main(void) { int readfd, writefd; /* create two FIFOs; OK if they already exist */ if((mkfifo(FIFO1, FILE_MODE) < 0) && (errno != EEXIST)) { printf("can't create %s\n", FIFO1); exit(1); } if((mkfifo(FIFO2, FILE_MODE) < 0) && (errno != EEXIST)) { unlink(FIFO1); printf("can't create %s\n", FIFO2); exit(1); } /* we don't handle the errors in the following. */ if((readfd = open(FIFO1, O_RDONLY, 0)) < 0) { perror("open FIFO1 failed"); unlink(FIFO1); exit(1); } if((writefd = open(FIFO2, O_WRONLY, 0)) < 0) { perror("open FIFO2 failed"); unlink(FIFO2); exit(1); } server(readfd, writefd); exit(0); }
/* client.c */ #include "fifo.h" void client(int readfd, int writefd) { /* ... */ } int main(int argc, char *argv[]) { int readfd, writefd; /* not handle errors in the following. */ writefd = open(FIFO1, O_WRONLY, 0); readfd = open(FIFO2, O_RDONLY, 0); client(readfd, writefd); close(readfd); close(writefd); unlink(FIFO1); unlink(FIFO2); exit(0); }以上程序为简洁起见,没有进行充分的错误检查(尤其是client.c),这里需要注意以下几点:
mkfifo fifo1 prog3 < fifo1 & prog1 < infile | tee fifo1 | prog2