簡體   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