我错误地使用close()吗?

时间:2017-05-09 19:22:12

标签: c linux process pipe fork

我试图创建一个运行任何给定Linux命令的程序,直到用户输入"停止"。

父亲应该生一个孩子,这个孩子也应该生孩子。

所以,让我们说A是父亲,B是儿子,C是孙子。

A - >从用户输入中读取命令 并将其发送到B

B - >从管道中读取命令 并将其发送到C

C - >从管道中读取命令 并使用execl。输出应发送到发送到B的管道,然后B将输出显示到屏幕。

所以我将有3个管道:1个从A到B,1个从B到C,1个从C到B。

管道p1:A到B
管道p2:B到C
管道p3:C到B

这是我的代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>


int main()
{   
    int p1[2], p2[2],p3[3];
    pipe(p1);
    pipe(p2);
    pipe(p3);
    char cmd[20],buffer[128];

    while(1<2)
    {

        printf("Type a cmd: \n");
        scanf("%s20",cmd);


        if(strcmp(cmd,"stop")==0)
        {
            break;
        }
        else
        {
            close(p3[1]);
            close(p3[0]);
            close(p1[0]);
            close(p2[1]);
            close(p2[0]);

            write(p1[1],&cmd,sizeof(char)*20);
            if(fork()==0)
            {   

                close(p1[1]);
                close(p2[0]);
                close(p3[1]);

                read(p1[0],&cmd,sizeof(char)*20);
                write(p2[1],&cmd,sizeof(char)*20);

                if(fork()==0)
                {
                    close(p1[0]);
                    close(p1[1]);
                    close(p2[1]);
                    close(p3[0]);

                    read(p2[0],&cmd,sizeof(char)*20);
                    char bin[20]="/bin/";
                    strcat(bin,cmd);

                    dup2(p3[1],1);
                    execl(bin,bin,NULL);
                    exit(1);
                }

                wait(0);
                dup2(p3[0],0);
                while(read(p3[0],&buffer,sizeof(char)))
                {
                    printf("%s",buffer);
                }
                exit(1);    
            }   
        }
        wait(0);
    }
    return 0;
}

我认为我错误地使用close()因为我不确切地理解它的作用。使用AFAIK是因为每次使用fork()时,FD都会重复使用。

到目前为止,它确实编译并运行,但如果我输入&#34; ls&#34;,程序将终止。

如果我删除了对close()的所有电话,&#34; ls&#34;会工作,但它会阻止,不允许我输入第二个命令。

1 个答案:

答案 0 :(得分:3)

您的程序会创建三个管道,然后在调用p2之前完全关闭其中两个管道(p3fork())。它还会同时关闭p1的读取结束。您的子进程将无法获得任何可用的文件句柄。

pipe(p1);
pipe(p2);
pipe(p3);
char cmd[20],buffer[128];

while(1<2) {
    ...
    else {
        close(p3[1]);
        close(p3[0]);
        close(p1[0]);
        close(p2[1]);
        close(p2[0]);
        ...
        write(p1[1],&cmd,sizeof(char)*20);

fork之后,孩子关闭单个剩余的管道文件句柄(这确实不是问题),然后尝试从已经由父项关闭的文件句柄中读取:

        if(fork()==0) {
            ...   
            close(p1[1]);
            ...
            read(p1[0],&cmd,sizeof(char)*20);

通常,你首先需要fork,然后关闭不需要的文件句柄,即对于父对子通信,只有父对象应该关闭读取结束,只有子对象应该关闭写入端。

当然,如果父级关闭了管道的一端,那么在循环的 next 迭代中,该文件句柄将无法用于新的子进程,因此您需要在那时创建一个新的pipe。或者保持所有fd在主程序中打开(但我不记得是否会导致管道问题)。

至于你从孩子到孙子的fd,你需要在做fork时以同样的方式对待他们。虽然我建议先做一个双过程实验。