如何使用dup2将stdin和stdout重定向到管道文件描述符?

时间:2020-01-06 07:47:56

标签: c pipe fork dup2 dup

我试图派生一个进程,将父级的stdout重定向到管道的写入端,并将子级的stdin重定向到管道的读取端。子级应该读取整数,直到父级打印零为止。父级打印从1到3,然后打印0。父级和子级都打印开始和结束的时间。由于父母无法打印到标准输出,因此它将开始时间和结束时间发送给孩子,孩子会同时打印其开始时间和完成时间以及父母的开始时间和结束时间。我本可以使用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

2 个答案:

答案 0 :(得分:0)

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

来自父级的初始消息是“ Cnt_Started_at_1234 \ n”。该子进程将读取令牌,但将尾部的'\ n'留在缓冲区中。

接下来,父母将发送“父母0 \ n”。子级将尝试解析为scanf("Parent %d", &i) && i)。这里有两个问题:

  • “父母”中的“ P”与初始消息中剩余的“ \ n”不匹配
  • 当格式更新为跳过前导空格时,“ i”的值将为零,这将导致while在读取“父项0”后退出。

可能的解决方案:允许scanf跳过空格,并消除i上的条件

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

答案 1 :(得分:0)

这里的问题是您的scanf语句。按照@ dash-o的建议,将其更改为空格。

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

由于您只是在i中评估while loop,因此不会输入“ i = 0”的情况。

下面是修改后的程序和输出,也请在您认为正确的情况下添加各种检查函数返回值/缓冲区溢出的方法-

#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