Странное письмо при прохождении символа через трубу - PullRequest
0 голосов
/ 05 февраля 2020

У меня есть входной файл с содержанием abcefghz. Я хочу использовать канал, чтобы дочерний процесс p1 отправлял 1 букву за раз своему родительскому процессу, который преобразует эту строку, используя код ASCII + 1 (abcefghz станет cdfghi{). Эта новая строка будет отправлена ​​через другой канал другому дочернему процессу, который напечатает результат в выходном файле.

Это код:

int main (int argc, char **argv)
{  
    pid_t pid1, pid2;
    int inputFile, outputFile;
    char stringaDalFile[256];
    char successivo;
    char stringaRisultato[256];
    int fd1[2], fd2[2]; // Pipe



    inputFile = open(argv[1], O_RDONLY);
    outputFile = open(argv[2], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);

    pipe(fd1);
    pipe(fd2);

    pid1 = fork();
    if (pid1 == 0) { 

        while ( (nread=read(inputFile, stringaDalFile, 1)) > 0) {
            close(fd1[0]);
            write(fd1[1], stringaDalFile, 1);
        }

        close(inputFile);
    }
    else { 
        close(fd1[1]);
        while ( read(fd1[0], stringaDalFile, 1) > 0 ) {

            successivo = converti(stringaDalFile[0]);

            write(fd2[1], &successivo, 1);
        }
    }

    pid2 = fork();
    if (pid2 == 0) { 

        close(fd2[1]);

        if (read(fd2[0], stringaRisultato, 1) == -1) {
            perror("Errore");
            exit(1);
        } 
        else {
            while ( read(fd2[0], stringaRisultato, 1) > 0 ) {
                write(STDOUT_FILENO, stringaRisultato, strlen(stringaRisultato)); //dbg
write(outputFile, stringaRisultato, strlen(stringaRisultato));
            }
        }

        close(outputFile);

        exit(0);
    }

    return 0;
}

char converti (char carattere) 
{
    return carattere+1;
}

К сожалению, это, похоже, не работает на 100% строка преобразуется, но программа вводит то, что кажется бесконечным l oop:

string is converted but infinite loop

Если I CTRL-C и gedit file2.txt, это его содержимое :

stranger character.

Как мне это исправить?

Ответы [ 2 ]

2 голосов
/ 05 февраля 2020

В вашем коде есть несколько проблем:

  1. Проблема real , здесь:

    write(outputFile, stringaRisultato, strlen(stringaRisultato));
    

    вы используете strlen(stringaRisultato), когда stringaRisultato имеет только один действительный символ в начале и не имеет NUL-терминатора после него. Просто используйте 1.

  2. Вы читаете только один символ за раз, вам не нужна строка из 256 символов. Измените stringaDalFile и stringaRisultato на две отдельные переменные char: carattereDalFile и carattereRisultante.

  3. В первом дочернем элементе (внутри if (pid1 == 0)) вы делаете close(fd1[0]) в целом oop. Вы должны убрать его из while.

  4. Опять же, у первого ребенка, вы не делаете exit(0). Это то, что заставляет вашу программу работать.

  5. Эта строка во втором дочернем элементе:

    if (read(fd2[0], stringaRisultato, 1) == -1) {
    

    полезна, только если вы хотите пропустить первый символ. Это предназначено? Если нет, удалите это if и используйте только while (read(...) > 0).

  6. Вы записываете все в канал fd2[1] перед запуском второго потомка (который будет читать из него) , Если входной файл слишком велик (несколько килобайт), это приведет к заполнению внутреннего буфера канала и заблокирует вашу программу на следующем write(), который она пытается выполнить, и никогда не завершится. Чтобы это исправить, вы должны запустить два дочерних процесса вместе. Для этого потребуется изменить структуру и логику c кода, но это выполнимо.

    Поскольку я не думаю, что это настоящая проблема, и эта программа, скорее всего, написана для образовательных целей, я оставлю что вам и исправить остальные пункты выше.


Рабочий код:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

char converti (char carattere);

int main (int argc, char **argv)
{
    pid_t pid1, pid2;
    int inputFile, outputFile;
    char carattereDalFile, carattereRisultante, successivo; // renamed
    int fd1[2], fd2[2];

    inputFile = open(argv[1], O_RDONLY);
    outputFile = open(argv[2], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);

    pipe(fd1);
    pipe(fd2);

    pid1 = fork();
    if (pid1 == 0) {
        close(fd1[0]); // <==  moved out of the while loop

        while (read(inputFile, &carattereDalFile, 1) > 0) {
            write(fd1[1], &carattereDalFile, 1);
        }

        close(inputFile);
        exit(0); // <== added
    } else {
        close(fd1[1]);

        while (read(fd1[0], &carattereDalFile, 1) > 0) {
            successivo = converti(carattereDalFile);
            write(fd2[1], &successivo, 1);
        }
    }

    pid2 = fork();
    if (pid2 == 0) {
        close(fd2[1]);

        if (read(fd2[0], &carattereRisultante, 1) == -1) {
            perror("Errore");
            exit(1);
        } else {
            while (read(fd2[0], &carattereRisultante, 1) > 0) {
                write(outputFile, &carattereRisultante, 1);
            }
        }

        close(outputFile);
        exit(0);
    }

    return 0;
}

char converti (char carattere)
{
    return carattere+1;
}
0 голосов
/ 05 февраля 2020

read возвращает количество прочитанных байтов, поэтому вы должны использовать его для добавления завершающего символа NUL в строку, которую он заполняет следующим образом

while ( (bytesread = read(inputFile, stringaDalFile, 1)) > 0) {
   stringaDalFile[bytesread] = '\0';
....
...