linux中管道(pipe)一谈

来源:互联网 发布:战国史se人物数据 编辑:程序博客网 时间:2024/06/02 06:47
/***********************************************  管道(pipe)是Linux上进程间通信的一种方式,其是半双工(数据流只能在一个方向上流动(还需要经过内核),及要么是接收,要么是发送),并且只能在父子进程 或 具有公共祖先的两个子进程间通信。  管道(pipe)一般是在调用fork函数之前调用pipe函数创建,这样的话,fork后子进程将得到父进程的两个管道描述符副本(相当于调用了两次dup)。/***********************************************相关函数:  #include <unistd.h>  int pipe(int fd[2])                        返回值:成功返回0,失败返回-1***********************************************/注意: 函数执行成功后为参数返回两个描述符,fd[0]为读而打                    开,fd[1]为写而打开很多系统在stat结构体st_size成员中储存管道中可用于读写字节数。但这是不可移植的。(对于struct stat不了解的请百度)使用管道有几点注意事项:1.当读(read)一个写(write)端已经关闭的管道,程序(read)将读完管道中所有数据后返回0。2.当写(write)一个读(write)端已经关闭的管道,将产SIGPIP信号,程序(write)返回-1,并将错误码置为EPIPE3.如果管道中数据为空,则(read)将永久堵塞直到有数据或写(write)端关闭。4.如果管道已被数据填满,则(write)将会堵塞直到管道中有空与空间 或 写端(read)关闭,(管道容量可用fpathconf函数得到,使用_PC_PIPE_BUF参数)。***********************************************/
实例1:    使用管道实现 ls -l | wc -c 操作分析:    执行ls -l后其结果将会被打印到终端(即使用到STDOUT_FILENO)标准输出,wc -c(统计单词数量)是从标准输入中得到内容(即使用到STDIN_FILENO)然后进行统计。思路:    子进程中调用exec函数族执行ls -l命令,并调用dup2函数将子进程中的fd[1]描述符复制为标准输出(STDOUT_FILENO),这用的话,但向标准输出中写数据是就等同于向管道中写数据。    对于父进程则调用exec函数族执行wc -c命令,然后调用dup2将fd[0]复制为标准输入,实例代码:#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>int main(int argc, char **argv){    pid_t pid;    int fd[2];    /**创建管道**/    if (pipe(fd) < 0) {        perror("pipe error");        return EXIT_FAILURE;    }    /**调用fork函数创建子进程**/    if ((pid = fork()) < 0) {        perror("fork error");        return EXIT_FAILURE;    } else if (0 == pid) {          close(fd[0]); /**关闭不必要的描述符**/        if (fd[1] != STDOUT_FILENO) {            if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {                perror("dup2 error to stdout");                return EXIT_FAILURE;            }            close(fd[1]);        }        execlp("ls", "ls", "-l", NULL);        exit(EXIT_SUCCESS);    }     //sleep(2);    close(fd[1]);    if (fd[0] != STDIN_FILENO) {        if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {            perror("dup2 error to stdin");            return EXIT_FAILURE;        }        close(fd[0]);    }    execlp("wc", "wc", "-c", NULL);    /**回收子进程的退出状态,避免产生僵死进程**/    if (waitpid(pid, NULL, 0) < 0) {        perror("waitpid error");        return EXIT_FAILURE;    }    return EXIT_SUCCESS;}
实例2:    实现分页功能 即more命令#include <stdio.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#define PAGE "/bin/more"#define MAXLINE 1024int main(int argc, char **argv){    pid_t pid;    int fd[2];    char line[MAXLINE];    char *page = NULL, *temp = NULL, *arg = NULL;    FILE *fp = NULL;    if (argc != 2) {        printf("Usage: %s <filename>\n", argv[0]);        return EXIT_FAILURE;    }    if ((fp = fopen(argv[1], "r")) == NULL) {        perror("fopen error");        return EXIT_FAILURE;    }    if (pipe(fd) < 0) {        perror("pipe error");        return EXIT_FAILURE;    }    if ((pid = fork()) < 0) {        perror("fork error");        return EXIT_FAILURE;    } else if (0 == pid) {        close(fd[0]);        int len;        while (fgets(line, MAXLINE, fp) != NULL) {            len = strlen(line);            int offset = 0, n = 0;            while (len) {                n = write(fd[1], line+offset, len);                offset += n;                len -= n;            }        }        if (ferror(fp)) {            perror("fgets errro");            return EXIT_FAILURE;        }        fclose(fp);        close(fd[1]);    }    close(fd[1]);    if (fd[0] != STDIN_FILENO) {        if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {            perror("dup2 error to stdin");            return EXIT_FAILURE;        }        close(fd[0]);    }    /***得到PAGE对应的环境参数***/    if ((page = getenv("PAGE")) != NULL) {        arg = page;    } else {        arg = PAGE;    }    /**    *strrchr函数判断'\'字符,    *在arg字符串中最后一次出现的位置    **/    if ((temp = strrchr(arg, '/')) != NULL) {        temp++;    } else {        temp = arg;    }    execl(arg, temp, NULL);    if (waitpid(pid, NULL, 0) < 0) {        perror("waitpid error");        return EXIT_FAILURE;    }    return EXIT_SUCCESS;}
原创粉丝点击