在 c.But 中实现管道不起作用

Implementing pipe in c.But it is not working

我正在尝试使用 C 语言实现管道。 我正在通过创建子进程

为由管道分隔的每个命令执行循环

以下是我的代码:

int main(int argc, char **argv)
{
    char *cmd,*splitcmd;
    int i,j,nargc=0,characters;
    char **cmdArray;
    size_t bufsize = 1024;
    int *pipefd;
    int pipeArrCount;
    pid_t pid,wpid;
    int status = 0;

    int savestdoutfd = dup(fileno(stdout));
    int savestdinfd = dup(fileno(stdin));

    cmd = (char *)malloc(bufsize * sizeof(char));
    characters = getline(&cmd,&bufsize,stdin);
//    printf("%s%d",cmd,characters);
    if(cmd[characters-1]=='\n')
    {
//        printf("in c");
        cmd[characters-1]='[=11=]';
        characters--;
    }

    cmdArray = (char**)malloc(sizeof(char *) * 100);
    splitcmd=strtok(cmd,"|");
//    printf("%s\n",cmd);
    while((splitcmd))
    {
        cmdArray[nargc] = splitcmd;
        if(cmdArray[nargc][(strlen(cmdArray[nargc]))-1]==' ')
            cmdArray[nargc][(strlen(cmdArray[nargc]))-1]='[=11=]';
        printf("%d    %s",nargc,cmdArray[nargc]);
        nargc++;
        splitcmd = strtok(NULL,"|");
    }

    pipefd=(int*)malloc(2*nargc*sizeof(int));
    printf("%d\n",nargc);
    pipeArrCount=2*(nargc-1);
    printf("%d\n",pipeArrCount);
    //exit(0);
    for(i=0;i<pipeArrCount;i)
    {
        printf("making pipe for process %d\n",i);
        pipe(pipefd+i);
        i=i+2;
    }


    //exit(0);
    for(i=0;i<nargc;i)
    {
        printf("parent count %d\n",i);
        if(i==0)
        {
            printf("Creating child %d\n",i);
            // As it is first process we need to make write end of the pipe as stdout.
            if ((pid=fork()) == 0)
            {
                printf("Creating first child %d for command %s\n",i,cmdArray[i]);
                printf("EXECUTING FIRST PROCESS\n");
                printf("Writing in pipe[%d]\n",2*i+1);

                //close(pipefd[0]);

                dup2(pipefd[2*i+1],fileno(stdout));
                //closing all other pipes
                for(j=0;j<(2*nargc);j++)
                {
                    //if(j!=2*i+1)
                        close(pipefd[j]);
                }
                system(cmdArray[i]);
                //dup2(savestdoutfd,fileno(stdout));
                printf("Stdout is again restored\n");
                //printf("pipe [%d] contains %d ",2*i+1,pipefd[2*i+1]);
                exit(0);
            }

        }
        else if(i!=nargc-1)
        {
            if (fork() == 0)
            {
                printf("EXECUTING MIDDLE PROCESS\n");
                printf("Command to execute %s \n",cmdArray[i]);
                printf("Reading from pipe[%d]\n",(2*(i-1)));
                printf("writing on pipe[%d]\n",(2*i)+1);
                dup2(pipefd[(2*(i-1))], 0); //Read end of the previous process pipe as stdin
                dup2(pipefd[(2*i)+1], 1); //Write end of the pipe of current process as stdout
                //closing all other pipes
                for(j=0;j<(2*nargc);j++)
                {
                    //if((j!=(2*(i-1))) && (j!=(2*i)+1))
                        close(pipefd[j]);
                }
                system(cmdArray[i]);
                exit(0);
            }
        }
        else
        {
            if (fork() == 0)
            {
                printf("Creating last child %d for command %s\n",i,cmdArray[i]);
                printf("Reading from pipe[%d]\n",(2*(i-1)));

                //close(pipefd[1]);

                dup2(pipefd[(2*(i-1))],fileno(stdin)); //Read from the end of the previous process pipe as stdin
                //printf("EXECUTING LAST PROCESS\n");
                //closing all other pipes
                for(i=0;j<(2*nargc);j++)
                {
                    //if(j!=(2*(i-1)))
                        close(pipefd[j]);
                }
                dup2(savestdoutfd,fileno(stdout));
                close(savestdoutfd);
                system(cmdArray[i]);
                dup2(savestdinfd,fileno(stdin));
                close(savestdinfd);
                exit(0);
            }
        }
        i=i+1;
        sleep(1);
    }
    while ((wpid = wait(&status)) > 0);
}

没有得到第二个命令的任何输出 现在我正在尝试执行这种 'A | B ' 类型的命令 如果执行代码

,命令和管道之间的space是必要的

我执行了你的代码。它适用于单个管道,例如:

ls | grep "a" and ls | wc.

它不适用于双管道,如:ls | grep "a" | wc。 错误是 错误的文件描述符

我没有调试这个错误,似乎 "else if" 子句中的文件描述符处理不当。不管怎样,你的问题是它不适用于像 A | B 这样的单管道。但确实如此。

希望对您有所帮助。

您离正确的解决方案不远了。但首先是一些通用的评论:

  • 您的代码未显示任何包含:请添加它们
  • 您正在从 malloc 转换 return 值。这在 C++ 中是必需的,但在 C 中不是:你应该写 cmd = malloc(bufsize * sizeof(char));
  • 您可以编写循环 for(i=0;i<pipeArrCount;i+=2) 删除 i=i+2 因为它在 C 中更常见,或者至少 for(i=0;i<pipeArrCount;) 以避免警告。

现在是您问题的真正原因。您为管道分配了一个大小为 2*nargc 的数组,但只初始化了 2*(nargc-1)。最后 2 个没有初始化,这应该是无害的,但是你关闭了整个数组for(j=0;j<(2*nargc);j++)。在我的测试中,它们是 0(可能是因为调试模式)所以你正在为你的孩子关闭标准输入。只需使用:

for(j=0;j<pipeArrCount;j++)
{
        close(pipefd[j]);
}

这还不是全部。你在最后一个命令中也有错字,你用 i 而不是 j 写了 for(i=0;j<(2*nargc);j++)。正如 Kulwant Singh 所指出的那样,它没有关闭任何允许代码 运行 仅使用 2 个命令的内容。

并且您还必须关闭 parent 进程中的管道。程序的结尾应该是:

    //closing all pipes
    for (j=0; j<pipeArrCount; j++) {
        close(pipefd[j]);
    }
    while ((wpid = wait(&status)) > 0);
}