c - 我错误地使用了 close() 吗?

标签 c linux process pipe fork

我正在尝试制作一个程序来运行任何给定的 Linux 命令,直到用户输入“停止”为止。

父亲要生 child ,父亲也要生 child 。

假设 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 都是重复的。

到目前为止,它确实可以编译和运行,但是如果我输入“ls”,程序就会终止。

如果我删除对 close() 的所有调用,“ls”将起作用,但它会阻塞,不允许我输入第二个命令。

最佳答案

您的程序创建三个管道,然后在调用 fork() 之前完全关闭其中两个(p2p3)。它还同时关闭了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,然后关闭不需要的文件句柄,即对于父子通信,只有父应该关闭读取端,只有子应该关闭写端。

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

至于从子代传给孙代的 fd,您需要在执行该fork 时以相同的方式对待它们。尽管我建议先进行双过程实验。

关于c - 我错误地使用了 close() 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43878248/

相关文章:

c - 如何在 LabWindows CVI 中读取网站上的文本?

mysql - 从数据库sql文件恢复单个mysql表

linux - "bash: nc: command not found"ssh 多跳错误

c - 将 fork 进程输出重定向到 NULL

Python execv 和管道输出

c++ - 如何使用 winapi 等待非子进程?

c - 高效的函数调用

c - 在c中求数组的中点,为什么我们使用(end + start)/2?请解释

c - 在c中使用fork并行进程在数组中搜索值

c - 定义与变量的存在