读取C块上的UNIX管道

我正在努力用类管道实现一个 shell.
typedef struct {
    char** cmd;
    int in[2];
    int out[2];
} cmdio;

cmdio cmds[MAX_PIPE + 1];

读取管道中的命令并将其存储在cmds中.

cmdio [i] .in是pipe()返回的输入管道的文件描述符对.对于从终端输入读取的第一个命令,它只是{fileno(stdin),– 1}. cmdin [i] .out对输出管道/终端输出类似. cmdio [i] .in与cmd [i-1] .out相同.例如:

$ls -l | sort | wc

CMD: ls -l 
IN: 0 -1
OUT: 3 4

CMD: sort 
IN: 3 4
OUT: 5 6

CMD: wc 
IN: 5 6
OUT: -1 1

我们将每个命令传递给process_command,它执行许多操作:

for (cmdi = 0; cmds[cmdi].cmd != NULL; cmdi++) {
    process_command(&cmds[cmdi]);
}

现在,在process_command中:

if (!(pid_fork = fork())) {
    dup2(cmd->in[0],fileno(stdin));
    dup2(cmd->out[1],fileno(stdout));    
    if (cmd->in[1] >= 0) {
        if (close(cmd->in[1])) {
            perror(NULL);
        }
    }
    if (cmd->out[0] >= 0) {
        if (close(cmd->out[0])) {
            perror(NULL);
        }
    }
    execvp(cmd->cmd[0],cmd->cmd);
    exit(-1);
}

问题是永远从管道中读取:

COMMAND $ls | wc
Created pipe,in: 5 out: 6
Foreground pid: 9042,command: ls,Exited,info: 0
[blocked running read() within wc]

如果,而不是与execvp交换过程,我只是这样做:

if (!(pid_fork = fork())) {
    dup2(cmd->in[0],fileno(stdout));
    if (cmd->in[1] >= 0) {
        if (close(cmd->in[1])) {
            perror(NULL);
        }
    }
    if (cmd->out[0] >= 0) {
        if (close(cmd->out[0])) {
            perror(NULL);
        }
    }

    char buf[6];
    read(fileno(stdin),buf,5);
    buf[5] = '\0';

    printf("%s\n",buf);
    exit(0);
}

它碰巧工作:

COMMAND $cmd1 | cmd2 | cmd3 | cmd4 | cmd5 
Pipe creada,in: 11 out: 12
Pipe creada,in: 13 out: 14
Pipe creada,in: 15 out: 16
Pipe creada,in: 17 out: 18
hola!
Foreground pid: 9251,command: cmd1,info: 0
Foreground pid: 9252,command: cmd2,info: 0
Foreground pid: 9253,command: cmd3,info: 0
Foreground pid: 9254,command: cmd4,info: 0
hola!
Foreground pid: 9255,command: cmd5,info: 0

可能是什么问题呢?

解决方法

你没有足够的关闭.在代码中:
if (!(pid_fork = fork())) {
    dup2(cmd->in[0],cmd->cmd);
    exit(-1);
}

在将管道复制到stdin和stdout(通过fileno())之后,需要关闭管道:

if (!(pid_fork = fork())) {
    dup2(cmd->in[0],fileno(stdout));    
    if (cmd->in[1] >= 0) {
        if (close(cmd->in[1])) {
            perror(NULL);
        }
    }
    if (cmd->out[0] >= 0) {
        if (close(cmd->out[0])) {
            perror(NULL);
        }
    }
    close(cmd->in[0]);  // Or your error checked version,but I'd use a function
    close(cmd->out[1]);     
    execvp(cmd->cmd[0],cmd->cmd);
    exit(-1);
}

程序没有完成,因为文件的写入结束仍然打开.另外,不要忘记,如果父进程(shell)创建管道,它必须关闭管道的两端.在开始学习管道管道时,没有关闭足够的管道可能是最常见的错误.

相关文章

/** C+⬑ * 默认成员函数 原来C++类中,有6个默认成员函数: 构造函数 析构函数 拷贝...
#pragma once // 1. 设计一个不能被拷贝的类/* 解析:拷贝只会放生在两个场景中:拷贝构造函数以及赋值运...
C类型转换 C语言:显式和隐式类型转换 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译...
//异常的概念/*抛出异常后必须要捕获,否则终止程序(到最外层后会交给main管理,main的行为就是终止) try...
#pragma once /*Smart pointer 智能指针;灵巧指针 智能指针三大件//1.RAII//2.像指针一样使用//3.拷贝问...
目录<future>future模板类成员函数:promise类promise的使用例程:packaged_task模板类例程...