C 中的管道问题 (Linux)

Pipe trouble in C (Linux)

我目前无法理解 non-duplex two-way children 和他们的 parent 之间的未命名管道通信。我正在尝试与超级 parent.

通信最多十个 children

目前我正在尝试让超级 parent 向每个 children 打招呼,然后 children 向 parent 打招呼。最后,超级 parent 确认他收到了每个 children.

的问候

我在添加管道之前测试了叉子,它们工作正常,产生了正确数量的 children。所以我几乎可以肯定问题出在我代码底部的两个 pipeCommunication() 方法中的一个(或两个)方法中。

当我运行程序时,它静止不动(好像在等待输入)。我预计它会卡在一个 while 循环中以供阅读,但是 我什至无法打印 main() 的第一行。

代码如下:

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


int NUM_CHILDREN;
int ID;


// Create the pipes
void createPipes(int[], int[]);

// Wait for the children processes
void waitForChildren(int);

// The Child pipe communication method
void childPipeCommunication(int, int, int);

// The Parent pipe communication method
void parentPipeCommunication(int, int, int);



// MAIN FUNCTION
int main(int argc, char *argv[])
{
    // NOT BEING PRINTED:
    printf("Hello");

    NUM_CHILDREN = argc - 1;

    // The file descriptors for the pipes
    int fd_childReads_ParentWrites[10][2];   // Parent should close 0, Child close 1
    int fd_parentReads_ChildWrites[10][2];   // Child should close 0, Parent close 1

    // Index of the child Array (0 to NUM_CHILDREN-1)
    int user;

    int pid;
    int pidArray[10]; // Stores each of the child's process id's

    // Fork the children and create the pipes
    for(user = 0; user < NUM_CHILDREN; user++)
    {
        // Create the pipes
        createPipes(fd_childReads_ParentWrites[user], fd_parentReads_ChildWrites[user]);

        // Fork the children
        pid = fork();

        if (pid < 0)   // Error occurred
        {
            printf("Fork Failed\n");
            exit(1);
        }
        else if (pid == 0)   // Child
        {
            break;
        }
        else if (pid) // Parent
        {
            pidArray[user] = pid;
        }
    }


    if (pid == 0) // CHILD
    {
        // Close the appropriate pipe ends
        close(fd_childReads_ParentWrites[user][1]);
        close(fd_parentReads_ChildWrites[user][0]);

        ID = getpid();
        int n = 0;

        // Enter pipe communication (user is the same as when it broke from the for loop)
        childPipeCommunication(ID, fd_childReads_ParentWrites[user][0],
                                fd_parentReads_ChildWrites[user][1]);

        // Finally, close the working child pipe ends
        close(fd_childReads_ParentWrites[user][0]);
        close(fd_parentReads_ChildWrites[user][1]);
    }
    else // PARENT
    {
        ID = getpid();
        user = 0;

        // Close the appropriate pipe ends
        for (user = 0; user < NUM_CHILDREN; user++)
        {
            close(fd_childReads_ParentWrites[user][0]);
            close(fd_parentReads_ChildWrites[user][1]);
        }

        // Go into Pipe Communication
        for(user = 0; user < NUM_CHILDREN; user++)
        {
            parentPipeCommunication(pidArray[user], fd_parentReads_ChildWrites[user][0], fd_childReads_ParentWrites[user][1]);
        }

        // Wait for the children
        waitForChildren();

        // Finally, close the working parent pipe ends
        for (user = 0;  user < NUM_CHILDREN; user++)
        {
            close(fd_childReads_ParentWrites[user][1]);
            close(fd_parentReads_ChildWrites[user][0]);
        }
    }
}



void createPipes(int fd1[2], int fd2[2])
{
    if (pipe(fd1) < 0)
    {
        printf("Pipe creation error!\n");
        exit(1);
    }

    if (pipe(fd2) < 0)
    {
        printf("Pipe creation error!\n");
        exit(1);
    }
}


void waitForChildren()
{
    int user;
    for (user = 0; user < NUM_CHILDREN; user++)
    {
        wait(NULL);
    }
}

下面是管道通信的方法

void childPipeCommunication(int childID, int fdReadFromParent, int fdWriteToParent)
{
    char buf_ChildReads[80];  
    int n = 0;

    while ((n = read(fdReadFromParent, buf_ChildReads, 80)) > 0)
        {
            buf_ChildReads[n] = 0;

            // CASE: CHILD RECEIVES HELLO FROM PARENT
            if(strcmp(buf_ChildReads, "Hi child.\n") == 0)
            {
                // Remove new line character
                buf_ChildReads[--n] = 0;

                // Acknowledge parent's hello and then send reply
                printf("Child %d: Reveived message [%s] from parent\n", childID, buf_ChildReads);
                write(fdWriteToParent, "Hello Parent\n", 13);
            }
        }
}


void parentPipeCommunication(int childID, int fdReadFromChild, int fdWriteToChild)
{
    char buf_ParentReads[80];  
    int n = 0;

    // Say hello to the child
    write(fdWriteToChild, "Hi child\n", 9);

    // Engage in communication with the child
    while ((n = read(fdReadFromChild, buf_ParentReads, 80)) > 0)
        {
            buf_ParentReads[n] = 0;

            // CASE: PARENT RECEIVES HELLO FROM CHILD
            if(strcmp(buf_ParentReads, "Hello Parent\n") == 0)
            {
                printf("Parent: I have received response from child %d\n", childID);
            }
        }
}

如果有人能看一下我的代码并告诉我如何正确实现parent和children之间的通信,我将不胜感激。

1) 问题:未打印 printf:

stdout 在 Unix 下通常是行缓冲的。尝试打印到 stderr(无缓冲),调用 fflush(stdout),或显式打印 "\n".

2) 问题:写入 & strcmp

请注意,您 write(fd, "Hi child\n", 9) 没有尾随 '[=15=]',但 strcmp 比较零终止字符串。因此,您的子进程永远不会响应。

通过管道的双向 IPC 有很多缺陷。参见 https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer

您将 NUM_CHILDREN 设置为命令行参数的数量。如果您未能提供任何参数,则它为零,不进入循环,pid 未初始化并且未定义将采用底部的两条路径中的哪一条。两者都会挂起。

在不从 stdin 读取并且发生挂起的情况下使用 printf 时,您可能需要使用 fflush 来获取输出。

接下来,您的 parent 正在等待没有句点的消息,而您的 child 正在发送句点。

最后,parent 和 child 都在循环,直到另一个关闭,所以来自第一个 child 的通信不会结束,之后的 children 永远不会被处理.