【问题标题】:Implementing pipe in c.But it is not working [closed]在c中实现管道。但它不起作用[关闭]
【发布时间】:2015-08-09 05:26:22
【问题描述】:

我正在尝试使用 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]='\0';
        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]='\0';
        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 ' 命令类型 如果你执行代码,命令和管道之间的空间是必要的

【问题讨论】:

  • 你能说得更具体些吗?期望什么?出了什么问题?
  • 我正在尝试使用 c 实现 unix 管道 ('|')。
  • 我正在尝试使用 c 实现 unix pipe ('|')。为此,我使用 pipe() 函数进行不同命令之间的通信。所以首先我尝试扫描命令并查看我需要多少个管道然后我多次调用管道函数。现在例如我有命令'cat out.c | sort' 这个程序所做的是得到一个管道,父进程为两个命令分叉两个进程,第一个命令是使用系统调用执行的,但是这个命令的输出应该在管道的写端,即 p[1] 然后关闭所有管道。一旦完成它.......
  • ........ 使用系统调用执行第二个命令并从管道的读取端读取,即 p[0]。
  • 请适当地提出问题

标签: c unix pipe fork


【解决方案1】:

您离正确的解决方案并不遥远。但首先是一些一般性的评论:

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

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

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

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

您还必须关闭父进程中的管道。程序结束应该是:

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

【讨论】:

  • 感谢您指出错误并提供解决方案。现在可以了。
【解决方案2】:

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

ls | grep "a" and ls | wc.

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

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

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-22
    • 2014-03-21
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    相关资源
    最近更新 更多