Форкинг процесса и использование каналов для передачи данных из файла построчно в дочерний процесс - PullRequest
0 голосов
/ 24 октября 2018

Мой проект состоит в том, чтобы разветвляться, а затем использовать родительский процесс, чтобы построчно считывать данные из файла, а затем отправлять каждую строку дочернему процессу, который должен использовать execve для отправки строки в качестве аргумента для bc, ивывод должен вернуться к родительскому процессу.Прямо сейчас я просто пытаюсь отправить данные ребенку и получить их должным образом, но это не работает.Я должен использовать select, чтобы выяснить, есть ли у дочернего элемента выходные данные для получения родителем.

У меня есть файл с 5 строками, и я использую цикл while для его просмотра.Я думал, что для каждой строки я получу строку от ребенка, но она делает только одну или две строки и останавливается.Тогда я получаю одну и ту же строку дважды по какой-то причине.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h> 
#include <sys/time.h>
#include <sys/types.h>
#include <errno.h>
#include <wait.h>


int main(int argc, char *argv[])
{
    alarm(60);

    fd_set rfds;
    fd_set r2fds;
    struct timeval tv;
    int retval;
    int retval2;

    int i = argc;
    int rc;
    FILE *fp;
    fp = fopen (argv[1],"r");

    char *args[3];
    int j = 0;
    while (j < i)
    {
        args[j] = argv[j+2];
        j++;
    }

    int stdin_pipe_fds[2], stdout_pipe_fds[2], stderr_pipe_fds[2];

    pipe(stdin_pipe_fds);
    pipe(stdout_pipe_fds);
    pipe(stderr_pipe_fds);

    rc = fork();
    if (rc == -1)
    {
        while (rc == -1)
        {
            rc = fork();
        }
    }

    pid_t child;
    pid_t parent;

    if (rc == 0)
    {
        child = getpid();

        close(stdin_pipe_fds[1]);
        close(stdout_pipe_fds[0]);
        close(stdout_pipe_fds[0]);

        close(0);
        dup(stdin_pipe_fds[0]);//, 0);
        close(stdin_pipe_fds[0]);
        close(1);
        dup(stdout_pipe_fds[1]);//,1);
        close(stdout_pipe_fds[1]);
        close(2);
        dup(stderr_pipe_fds[1]);//,2);
        close(stderr_pipe_fds[1]);
    }

    if (rc > 0)
    {
        parent = getpid();

        close(stdin_pipe_fds[0]);
        close(stdout_pipe_fds[1]);
        close(stderr_pipe_fds[1]);
    }

    char str[100];
    char buf2[100];
    char buf[100];

    FD_ZERO(&rfds);
    FD_SET(stdout_pipe_fds[0], &rfds);

    tv.tv_sec = 1;
    tv.tv_usec = 0;



    while ((fgets(str,100,fp)) != NULL)
    {       
        if (rc > 0)
        {   
            int wstatus;
            int wsta;
            int status;
            wsta = write(stdin_pipe_fds[1],str,strlen(str));
            retval = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);

            if (FD_ISSET(stdout_pipe_fds[0], &rfds))
            {
                wstatus = read(stdout_pipe_fds[0], buf2, 100);
                printf("From child: %s\n",buf2);
                if (wstatus == -1)
                {
                    printf("read failed\n");
                    //continue;
                }
                //wsta = write(stdin_pipe_fds[1],str,strlen(str));
            }


        }

        if (rc == 0)
        {
            alarm(60);

            scanf("%s",buf);
            printf("%s", buf);
        }       
    }

    fclose(fp);
}

1 Ответ

0 голосов
/ 24 октября 2018

В дочернем

вы закрываете stdout_pipe_fds [0] дважды, а не stderr_pipe_fds [0].

scanf ("% s", buf) удалит символ новой строки из строки;Вы можете не хотеть этого.Stdout, если вы начали с терминала, будет буферизироваться по линии;то есть потребуется новая строка для запуска фактической записи.Поскольку вы прокрались и заменили базовый FD, он не знает, что новая стратегия буферизации может быть подходящей.

В родительском:

вы рассматриваете чтение и запись так, как будто они возвращаютстатус;они возвращают количество прочитанных или записанных байтов.Если он читает 0 байтов, buf будет содержать значения из предыдущего чтения.Я не уверен в предназначении read (), я бы предположил, что он просто все испортилЯ думаю, вам нужно нарисовать картину того, как связаны файловые дескрипторы.

Предложения: Существует общепринятая идиома при использовании fork:

if ((rc = fork()) == 0) {
    /* do child stuff */
} else if (rc != -1) {
    /* do parent stuff */
} else {
    /* do error stuff */
}

, которая в основном соблюдается, чтобы избежать деформациимозги народов.Это действительно трудно читать, когда оно чередуется.Буква «K» в K & R однажды выдвинула это: «если вы настолько умны, насколько можете, когда пишете, как вы будете отлаживать его?»

The close (0);DUP ();гораздо лучше выражается как dup2 (fd, 0).Тот факт, что вы можете скомпилировать код на своем компьютере, гарантирует правильную работу dup2.

...