通过管道传递字符时出现奇怪的字母

Strange letter when passing character through a pipe

我有一个内容为 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% 工作,字符串已转换但程序进入似乎无限循环:

如果我CTRL-Cgedit file2.txt,这是它的内容:

.

我该如何解决这个问题?

read returns 读取的字节数,因此您应该使用它来将 NUL 终止字符添加到它填充的字符串中,如下所示

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

您的代码中存在一些问题:

  1. 真正的问题,这里:

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

    stringaRisultato 开头只有一个有效字符而后面没有 NUL-terminator 时,您正在使用 strlen(stringaRisultato)。只需使用 1 即可。

  2. 您一次只读一个字符,不需要 256 个字符的字符串。将 stringaDalFilestringaRisultato 更改为两个单独的 char 变量:carattereDalFilecarattereRisultante.

  3. 在第一个 child(在 if (pid1 == 0) 内)中,您正在循环执行 close(fd1[0])。您应该将其移出 while.

  4. 同样在第一个 child 中,你没有做 exit(0)。这就是导致您的程序保持 运行.

  5. 的原因
  6. 这一行里面第二个child:

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

    仅在您想跳过第一个字符时才有用。这是故意的吗?如果不是,请删除 if 并仅使用 while (read(...) > 0).

  7. 在开始第二个 child(将从中读取)之前,您正在将所有内容写入管道 fd2[1]。如果输入文件太大(一些 KB),这将导致管道内部缓冲区被填满,并会在下一个 write() 尝试执行时阻塞您的程序,使其永远不会结束。要解决此问题,您应该同时启动两个 child 进程。这将需要更改代码的结构和逻辑,但这是可行的。

    因为我认为这不是这里的真正问题,而且这个程序很可能是出于教育目的而编写的,所以我将把它留给你并解决以上其余问题。


工作代码:

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