管道

匿名管道

简介

管道是UNIX系统中最古老的IPC形式,简单来说,管道是进程之间最简单的通信方式.

局限性

  • 历史上,管道是半双工的,也就是说数据只能在一个方向上流动.比如我们指定了管道x用于a和b之间的通信,a为写入进程,b为读取进程.那么此时b是无法写入信息传送给a的(下文会有说明).现在某些系统提供了全双工管道,但是考虑到可移植性的问题,我们不应假设系统支持.
  • 使用场景有限.因为管道是进程创建并存在于内核中的,所以管道并不能跨越两个没有亲缘关系的进程,即它们不是同属相同的祖先进程.

例子

要求:父进程读取路径并传送给子进程,子进程读出文件内容并传送给父进程.

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <limits.h>
#include<fcntl.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<sys/types.h>

#define bufSize 65535

void client(int,int);
void server(int,int);


int main(int argc, char const *argv[]) {
    //fd[0]为读入端,fd[1]为写入端
    int pipeForPath[2];
    int pipeForContent[2];

    pid_t childpid;

    pipe(pipeForPath);
    pipe(pipeForContent);

    if((childpid = fork()) == 0) {
        //关闭Content的读以及Path的写
        close(pipeForContent[0]);
        close(pipeForPath[1]);

        client(pipeForPath[0], pipeForContent[1]);

        exit(0);
    }

    //关闭Content的写以及Path的读
    close(pipeForContent[1]);
    close(pipeForPath[0]);

    server(pipeForContent[0], pipeForPath[1]);

    //等待子进程退出
    waitpid(childpid, NULL, 0);
    exit(0);
}


void client(int readfd, int writefd) {
    int fd;
    size_t n;
    char readBuf[bufSize];
    char path[PATH_MAX + 1];

    //从管道中读取路径,出错则退出
    if((n = read(readfd, path, PATH_MAX + 1)) == 0){
        printf("Read Error\n");
        exit(0);
    }

    path[n] = '\0';

    //打开指定文件,出错则写入错误信息并退出
    if((fd = open(path, O_RDONLY)) < 0){
        char error[] = "Open File Error\n";
        write(writefd, error, strlen(error));
        exit(0);
    }

    //将文件内容读出并写入管道                                                                            
    while((n = read(fd, readBuf, bufSize-1)) != 0) {
        write(writefd, readBuf ,n);
    }

    close(fd);
}

void server(int readfd, int writefd) {
    size_t length,n;
    char path[PATH_MAX+1];
    char readBuf[bufSize];

    printf("Please enter the file path: ");
    scanf("%s", path);

    length = strlen(path);

    //向管道中写入路径
    write(writefd, path, length);

    //读取管道的返回值并输出到控制台.
    while((n = read(readfd, readBuf, bufSize)) > 0)
        printf("%s",readBuf);

}

全双工管道

全双工管道在某些操作系统中已经实现,其原理其实很简单,就是在全双工管道中"藏着"两条半双工管道.
假设我们创建了一条全双工管道A,A中包含着半双工管道a和b.此时fd[0]的read是从管道a中读取,而fd[0]的write是写入管道b.fd[1]则与fd[0]相反.
通过这种方式我们就实现了全双工管道.

popen和pclose

首先来看一下两个函数的函数原型.

    #include <stdio.h>

    FILE *popen(const char *command, const char *type)
        //成功则返回描述符,失败则返回NULL
    int pclose(FILE *stream)
        //成功则为Shell的终止状态,出错则为-1
  • popen:
    • popen打开一个进程,通过shell执行我们传递的command命令.
    • type参数指明了我们对于进程输入/输出的操作方式
  • type参数:
    • 'r' : 调用进程读出command的标准输出
    • 'w' : 调用进程写入command的标准输入
posted @ 2017-03-10 18:27  XLLL  阅读(262)  评论(0编辑  收藏  举报