繁体   English   中英

使用 C 中的管道在 ipc 中连续写入和读取消息

[英]Writing and reading messages continuously in ipc with pipes in C

我编写了一个程序,其中父进程创建了两个子进程。 父进程写入第一个或第二个子进程,子进程读取消息。

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

#define MSGSIZE 64

char msgbuf[MSGSIZE];

int main(){

    int p1[2];
    int p2[2];
    int nread;
    int choice = 0;
    pid_t child_a,child_b;


    if(pipe(p1) == -1){
        printf("error in creating pipe\n");
        exit(-1);
    }

    if(pipe(p2) == -1){
        printf("error in creating pipe\n");
        exit(-1);
    }

    child_a = fork();

if (child_a == 0) {
    dup2(p1[0], STDIN_FILENO);
    read(STDIN_FILENO,msgbuf,MSGSIZE); 
    printf("%d receives message: %s\n",getpid(),msgbuf);
    close(p1[0]); 
    close(p1[1]);
} else {
    child_b = fork();

    if (child_b == 0) {
        dup2(p2[0], STDIN_FILENO); 
        read(STDIN_FILENO,msgbuf,MSGSIZE);
        printf("%d receives message: %s\n",getpid(),msgbuf);
        close(p2[0]); 
        close(p2[1]); 
    } else {
        /* Parent Code */
        // Write something to child A
        while(1){
        printf("<child_to_receive_msg> <message>\n");
        scanf("%d %s",&choice,msgbuf);
        switch(choice){
        case 1:
            usleep(250);
            write(p1[1], msgbuf, MSGSIZE);
            break;
        // Write something to child B
        case 2:
            usleep(250);
            write(p2[1], msgbuf, MSGSIZE);
            break;
        case -1: 
            usleep(250);
            printf("parent waiting");
            wait(NULL);
            exit(-1);
            break;
        }
       }
      }
    }

    return 0;
}

我的问题是我希望父进程继续写入子进程。 使用上面的代码,一旦它写入 child 或 child 2,它就不会再次写入或至少子进程不会再次读取它。 我不知道是否有可能做到这一点。

我尝试将 while 循环放在程序的开头,但这会导致每次都创建另一个子进程。

这是我的解决方案,然后是一些解释:

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

#define MSGSIZE 64

void read_process(int fh) {

        assert(-1 < fh);

        char msgbuf[MSGSIZE];

        ssize_t retval = 0;

        while (-1 < retval) {
                retval = read(fh, msgbuf, MSGSIZE);
                printf("%d receives message: %s\n", getpid(), msgbuf);
                close(fh);
        }

}

void write_process(int fh_child_1, int fh_child_2) {

        assert(-1 < fh_child_1);
        assert(-1 < fh_child_2);

        char msgbuf[MSGSIZE];
        int choice = -1;

        while (1) {
                printf("<child_to_receive_msg> <message>\n");

                scanf("%d %64s", &choice, msgbuf);

                switch (choice) {
                        case 1:
                                write(fh_child_1, msgbuf, MSGSIZE);
                                break;
                        // Write something to child B
                        case 2:
                                write(fh_child_2, msgbuf, MSGSIZE);
                                break;
                        case -1:
                                printf("parent waiting");
                                wait(NULL);
                                exit(-1);
                                break;
                }
        }
}

int main() {

        /* 0 will be for reading, 1 for writing */
        int p1[2];
        int p2[2];

        pid_t pid;

        if (pipe(p1) == -1) {
                printf("error in creating pipe\n");
                exit(-1);
        }

        /* Don't create 2nd pipe yet, we don't require it here and save us to
         * tear it down in child 1 */

        pid = fork();

        if (pid == 0) {
                close(p1[1]); /* not needed here */
                p1[1] = -1;
                read_process(p1[0]);
                exit(EXIT_SUCCESS);

        } else {
                /* Nobody is going to read from pipe 1 here again */
                close(p1[0]);
                p1[0] = -1; /* Mark fh as invalid */

                if (pipe(p2) == -1) {
                        printf("error in creating pipe\n");
                        exit(-1);
                }

                pid = fork();

                if (pid == 0) {
                        close(p1[1]);
                        p1[1] = -1;

                        close(p2[1]);
                        p2[1] = -1;

                        /* Ensure we did not forget an fh */
                        assert(-1 == p1[0]);
                        assert(-1 == p1[1]);
                        assert(-1 == p2[1]);

                        read_process(p2[0]);
                        exit(EXIT_SUCCESS);

                } else {
                        /* Parent Code */

                        close(p2[0]);
                        p2[0] = -1;

                        assert(-1 == p1[0]);
                        assert(-1 == p2[0]);

                        write_process(p1[1], p2[1]);
                        exit(EXIT_SUCCESS);
                }
        }

        return 0;
}

如前所述,您的主要问题是您的子进程不会循环,而是只读取一次。

有几个注意事项,我先说一般的,然后再说更多的系统编程特定的。

您的主要问题,丢失的循环,隐藏在您的代码之下,有点像意大利面。

C 提供了构建代码的方法,例如函数。 函数不仅用于重用代码,还可以用于总结您的代码:不要将子进程的代码直接粘贴到您需要的地方,而是将代码转移到专用函数并调用该函数。 这对理解代码的基本结构有很大帮助:

close(p1[1]); /* not needed here */
p1[1] = -1;

read_process(p1[0]);
exit(EXIT_SUCCESS);

很明显,基本思想是什么,不是吗? 如果您想了解读取过程的详细信息,请检查read_process函数。

小心你的资源。 仅在需要时才分配尽可能少的资源。 尽快释放它们并将它们标记为已释放 - 请参阅管道文件句柄。

最后,如果你fork,这个过程基本上是复制的。 您创建了第二个进程,并为它提供了所有(好吧,大多数)父进程资源的副本/克隆

您的情况下的文件句柄是克隆的。 例如关闭p1[0]在你的孩子不影响p1[0]在您的父母,因为他们是不一样的。 这也意味着,在分叉之后,您应该立即考虑所有可用资源,并立即删除您不需要的所有资源,例如

pid = fork();
if(0 == pid) {
    close(p1[1]); /* not needed here */
    p1[1] = -1;
    read_process(p1[0]);
    exit(EXIT_SUCCESS);
}

你的第一个孩子不需要p1[1] ,因此关闭它并将其标记为关闭和无效。

可能还有很多话要说,但这些是我立即想到的要点。

其中一些可能看起来并不笨拙,但是随着您越来越有经验,并且您的代码库不断增长,您会欣赏这些东西,至少我每天做的事情越来越多。 至于代码,当然还有很多错误隐藏在那里,尽管我希望你明白基本的想法;)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM