繁体   English   中英

读取C块上的UNIX管道

[英]UNIX pipes on C block on read

我正在努力用类管道实现一个shell。

typedef struct {
    char** cmd;
    int in[2];
    int out[2];
} cmdio;

cmdio cmds[MAX_PIPE + 1];

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

cmdio[i].inpipe()返回的输入管道的文件描述符对。 对于从终端输入读取的第一个命令,它只是{fileno(stdin), - 1}。 cmdin[i].out类似于输出管道/终端输出。 cmdio[i].incmd[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(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);
        }
    }

    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, Exited, info: 0
Foreground pid: 9252, command: cmd2, Exited, info: 0
Foreground pid: 9253, command: cmd3, Exited, info: 0
Foreground pid: 9254, command: cmd4, Exited, info: 0
hola!
Foreground pid: 9255, command: cmd5, Exited, info: 0

可能是什么问题呢?

你没有足够的关闭。 在代码中:

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);
}

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

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);
        }
    }
    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)创建管道,它必须关闭管道的两端。 在开始学习管道管道时,没有关闭足够的管道可能是最常见的错误。

好吧,我终于解决了。

在父进程上,就在整个子for​​k之后,我把:

f (cmd->in[0] != fileno(stdin)) {
    close(cmd->in[0]);
    close(cmd->in[1]);
} 

瞧。 之前我曾做过类似的事情,但我输入错误并close(cmd->out[0]); 代替。 就是这样了。 现在有道理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM