如何使用 dup2 将标准输入和标准输出重定向到管道文件描述符?

How to use dup2 to redirect stdin and stdout to pipe file descriptors?

我试图分叉一个进程,并将 parent 的标准输出重定向到管道的写入端,将 child 的标准输入重定向到管道的读取端。 child 应该读取整数,直到 parent 打印出零。 parent 从 1 打印到 3,然后打印 0。parent 和 child 都打印它们开始和结束的时间。因为 parent 无法打印到标准输出,所以它会将它的开始和结束时间发送到 child 并且 child 打印它的开始时间和结束时间以及 parents 开始时间和结束时间。我本可以使用 dup 并将 stdout 重定向到另一个文件描述符,但我选择让它变得简单。该程序非常简单,但我得到的输出不符合场景。

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int main() 
{ 
    int fd[2];
    int p = pipe(fd);
    int ch = fork();

    if (ch)
    {
        // Parent - Counts from 1 to 3
        int dp = dup2(fd[1], 1);
        printf("Cnt_Started_at_%d\n", time(NULL));
        for (int i = 0; i <= 3; i++)
        {
            printf("Parent %d\n", i);
            sleep(1);
        }
        printf("0\n");
        printf("Cnt_Finished_at_%d\n", time(NULL));
    }
    else 
    {
        // Child - Terminated by 0
        int dp = dup2(fd[0], 0);
        printf("Trm_Started_at_%d\n", time(NULL));
        char buffer[100];
        scanf("%s", buffer);
        printf("%s\n", buffer);

        int i; 
        while (scanf("Parent %d", &i) && i)
            printf("Recieved: %d\n", i);

        scanf("%s", buffer);
        printf("%s\n", buffer);
        printf("Trm_Finished_at_%d\n", time(NULL));
    }
}

输出:

Trm_Started_at_1578295974
Cnt_Started_at_1578295974
Parent
Trm_Finished_at_1578295978

根本问题是使用 'scanf %s' 来阅读消息。回想一下,'%s' 在遇到白色 space 时将停止读取,并将白色 space 放回缓冲区。

来自家长的初始消息是 'Cnt_Started_at_1234\n'。此子进程将读取令牌,但会将尾随的“\n”留在缓冲区中。

接下来家长会发送 'Parent 0\n'。 Child 将尝试解析这是 scanf("Parent %d", &i) && i)。这里有两个问题:

  • 'Parent' 中的 'P' 将与初始消息中剩余的“\n”不匹配
  • 当格式更新为跳过前导spaces时,'i'的值将为零,这将导致while读取[=33=后退出].

可能的解决方案:允许 scanf 跳过 spaces,并消除 i

上的条件
    while (scanf(" Parent %d", &i) == 1 )
            printf("Recieved: %d\n", i);

这里的问题出在你的 scanf 语句上。按照@dash-o 的建议,将其更改为处理空格。

另一个问题是,首先i = 0。您需要修改 while 以适应 0。

由于您仅在 while loop 中评估 i,因此您不会进入“i=0”案例。

下面是修改后的程序和输出,另外,请添加各种检查 return 函数值/缓冲区溢出,如您认为正确 --

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int main()
{
        int fd[2];
        int p = pipe(fd);
        int ch = fork();

        if (ch)
        {
                // Parent - Counts from 1 to 3
                int dp = dup2(fd[1], 1);
                printf("Cnt_Started_at_%d\n", time(NULL));
                for (int i = 0; i <= 3; i++)
                {
                        printf("Parent %d\n", i);
                        sleep(1);
                }
                printf("0\n");
                printf("Cnt_Finished_at_%d\n", time(NULL));
        }
        else
        {
                // Child - Terminated by 0
                int dp = dup2(fd[0], 0);
                printf("Trm_Started_at_%d\n", time(NULL));
                char buffer[100];
                scanf("%s", buffer);
                printf("%s\n", buffer);

                int i;
                while (scanf(" Parent %d", &i) && i >= 0) // notice change here ...
                        printf("Recieved: %d\n", i);

                scanf("%s", buffer);
                printf("%s\n", buffer);
                printf("Trm_Finished_at_%d\n", time(NULL));
        }
}

OUTPUT --
$ ./main.out
Trm_Started_at_1578303662
Cnt_Started_at_1578303662
Recieved: 0
Recieved: 1
Recieved: 2
Recieved: 3
0
Trm_Finished_at_1578303666