简体   繁体   English

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

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

I was trying to fork a process and redirect stdout of the parent to the writing end of the pipe and stdin of the child to the reading end of the pipe.我试图分叉一个进程并将父级的 stdout 重定向到管道的写入端,将子级的 stdin 重定向到管道的读取端。 The child is supposed to read integers until the parent prints zero.孩子应该读取整数,直到父母打印零。 the parent prints from 1 to 3 and then prints 0. Both the parent and the child prints the time when they start and when they finish.父母打印从 1 到 3,然后打印 0。父母和孩子都打印他们开始和完成的时间。 since the parent can't print to stdout it sends it's starting and finishing time to the child and the child prints both its starting time and finishing time and parents starting time and finishing time.由于父母无法打印到标准输出,它会将它的开始和完成时间发送给孩子,孩子会打印其开始时间和完成时间以及父母的开始时间和完成时间。 I could've used dup and redirected stdout to another file descriptor but I chose to make it simple.我本可以使用 dup 并将 stdout 重定向到另一个文件描述符,但我选择让它变得简单。 The program is very simple but the output that I get doesn't make scene.该程序非常简单,但我得到的输出并没有出现。

#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));
    }
}

Output:输出:

Trm_Started_at_1578295974
Cnt_Started_at_1578295974
Parent
Trm_Finished_at_1578295978

The root issue is the usage of 'scanf %s' to read messages.根本问题是使用“scanf %s”来读取消息。 Recall that '%s' will stop reading when it encounter white space, and will put the white space back into the buffer.回想一下,“%s”在遇到空白时将停止读取,并将空白放回缓冲区。

The initial message from the parent is 'Cnt_Started_at_1234\\n'.来自父级的初始消息是“Cnt_Started_at_1234\\n”。 This child process will read the token, but will leave the trailing '\\n' in the buffer.此子进程将读取令牌,但会将尾随的 '\\n' 留在缓冲区中。

Next the parent will send 'Parent 0\\n'.接下来,父级将发送“父级 0\\n”。 The Child will attempt to parse this is scanf("Parent %d", &i) && i) . Child 将尝试解析这是scanf("Parent %d", &i) && i) Two issues here:这里有两个问题:

  • The 'P' from 'Parent' will not match the left over '\\n' from the initial message 'Parent' 中的 'P' 将与初始消息中左边的 '\\n' 不匹配
  • When the format is updated to skip of leading spaces, the value of 'i' will be zero, which will cause the while to exit after reading 'Parent 0'.当格式更新为跳过前导空格时,'i' 的值将为零,这将导致while在读取 'Parent 0' 后退出。

Possible solution: Allow the scanf to skip of spaces, and eliminate the condition on i可能的解决方案:允许 scanf 跳过空格,并消除 i 上的条件

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

The problem here is with your scanf statement.这里的问题在于您的 scanf 语句。 As suggested by @dash-o, change it to treat spaces.按照@dash-o 的建议,将其更改为处理空格。

Another problem is that, first i = 0 .另一个问题是,首先i = 0 You need to modify your while to accomodate 0.您需要修改您的时间以适应 0。

Since you are only evaluating i in your while loop , you won't be entering for ``i=0``` case.由于您只在while loop评估i ,因此您不会输入 ``i=0``` 情况。

Below is the modified program and the output, also, please add various checks for return values of the functions / buffer overflows as you deem right --以下是修改后的程序和输出,此外,请添加您认为正确的函数返回值/缓冲区溢出的各种检查-

#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

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

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