Как использовать dup2 для перенаправления stdin и stdout в дескрипторы файлов конвейера? - PullRequest
0 голосов
/ 06 января 2020

Я пытался раскошелиться на процесс и перенаправить стандартный вывод родительского элемента в конец записи канала, а стандартный вывод дочернего элемента - в конец чтения канала. Предполагается, что ребенок читает целые числа, пока родитель не напечатает ноль. родитель печатает от 1 до 3, а затем печатает 0. И родитель, и потомок печатают время, когда они начинают и когда они заканчивают sh. так как родитель не может печатать на стандартный вывод, он отправляет свое начальное и конечное время ребенку, а ребенок печатает как свое начальное и конечное время, так и родительское начальное и конечное время. Я мог бы использовать 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 голосов
/ 06 января 2020

Проблема здесь в вашем выражении scanf. Как предлагает @ da sh -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
0 голосов
/ 06 января 2020

Проблема root заключается в использовании 'scanf% s' для чтения сообщений. Вспомните, что «% s» прекратит чтение, когда обнаружит пробел, и вернет пробел обратно в буфер.

Исходное сообщение от родителя - Cnt_Started_at_1234 \ n '. Этот дочерний процесс будет читать токен, но оставит завершающий символ '\ n' в буфере.

Затем родительский объект отправит сообщение «Parent 0 \ n». Ребенок попытается разобрать это scanf("Parent %d", &i) && i). Здесь есть две проблемы:

  • 'P' из 'Parent' не будет совпадать с левым и более '\ n' от исходного сообщения
  • Когда формат обновляется до пропуска ведущих пробелов, значение 'i' будет равно нулю, что приведет к выходу while после чтения 'Parent 0'.

Возможное решение: разрешить scanf пропускать пробелы и исключить условие на I

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