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

C 如何使用dup2将stdin和stdout重定向到管道文件描述符?,c,pipe,fork,dup2,dup,C,Pipe,Fork,Dup2,Dup,我试图分叉一个进程,将父进程的stdout重定向到管道的写入端,将子进程的stdin重定向到管道的读取端。子对象应该读取整数,直到父对象打印零为止。父对象从1打印到3,然后打印0。父对象和子对象都打印开始和结束的时间。由于父级无法打印到标准输出,它会将其开始时间和结束时间发送给子级,子级同时打印其开始时间和结束时间以及父级开始时间和结束时间。我本可以使用dup并将标准输出重定向到另一个文件描述符,但我选择使其简单化。这个程序很简单,但我得到的输出却不符合实际 #include <stdio

我试图分叉一个进程,将父进程的stdout重定向到管道的写入端,将子进程的stdin重定向到管道的读取端。子对象应该读取整数,直到父对象打印零为止。父对象从1打印到3,然后打印0。父对象和子对象都打印开始和结束的时间。由于父级无法打印到标准输出,它会将其开始时间和结束时间发送给子级,子级同时打印其开始时间和结束时间以及父级开始时间和结束时间。我本可以使用dup并将标准输出重定向到另一个文件描述符,但我选择使其简单化。这个程序很简单,但我得到的输出却不符合实际

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

根本问题是使用“scanf%s”读取邮件。回想一下,当“%s”遇到空白时,它将停止读取,并将空白放回缓冲区

来自父级的初始消息是“Cnt\u Started\u at\u 1234\n”。此子进程将读取令牌,但将在缓冲区中保留尾随“\n”

下一步,父级将发送“父级0\n”。子级将尝试分析这是
scanf(“父级%d”,&i)和&i)
。这里有两个问题:

  • “Parent”中的“P”与初始消息中剩余的“\n”不匹配
  • 当格式更新为跳过前导空格时,“i”的值将为零,这将导致
    在读取“父0”后退出
可能的解决方案:允许scanf跳过空格,并消除i上的条件

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

这里的问题在于您的scanf声明。按照@dash-o的建议,将其更改为处理空格

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

由于您仅在
while循环中计算
i
,因此不会输入“i=0”案例

下面是修改后的程序和输出,另外,请添加各种检查,以确定函数/缓冲区溢出的返回值是否正确--

#包括
#包括
#包括
#包括
#包括
int main()
{
int-fd[2];
int p=管道(fd);
int ch=fork();
如果(ch)
{
//父级-计数范围为1到3
int-dp=dup2(fd[1],1);
printf(“Cnt_在_%d\n开始”,时间(NULL));
for(inti=0;i=0)//注意这里的变化。。。
printf(“收到:%d\n”,i);
scanf(“%s”,缓冲区);
printf(“%s\n”,缓冲区);
printf(“Trm_在%d\n完成”,时间(NULL));
}
}
输出--
$/main.out
Trm_从_157803662开始
Cnt_于_157803662启动
收到:0
收到:1
收到:2
收到:3
0
Trm_在_157803666完成

dup在这里有什么用?您想让家长只写而让孩子只读吗?在这种情况下,你可能想考虑关闭孩子和父母的FD。是的,这就是我想要的。我考虑过这样做,但我在dup2的手册页中看到,如果新的文件描述符以前打开过,它会先关闭它,然后分配它。可能会添加更多的错误检查-例如fork失败。此外,缓冲区溢出在scanf@EdHeal这段代码只是我试图理解管道。如果我在写一个真正的程序,我会确定的。是的,很好。谢谢
    while (scanf(" Parent %d", &i) == 1 )
            printf("Recieved: %d\n", i);
#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