子进程和父进程之间的管道(pipe())

4

我写了这段代码实现子进程和父进程之间的pipe()通信。我需要确认一下这段代码是否正确。顺便说一句,它会给出应该看到的答案!

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>



int main(int argc, char *argv[]){
    pid_t pid;
    int fd[2];
    char buf[20];

pipe(fd);


switch(pid = fork()){

    case -1:
        perror("pipe");
        exit(1);

    case 0: 
        /*child process*/
        close(fd[1]);
        read(fd[0], buf, 20);
        printf("Child read message from parent: %s\n", buf);
        exit(1);
        break;

    default:
     /*parent process*/
        close(fd[0]);
        write(fd[1], "Hello from parent\n", 17);
        break;
    } 
    return 0;

}

2
这不是一个代码审查网站。你有什么问题? - Brian McFarland
1
实际上,我需要验证是否有编写这些代码的最佳实践。对于这个操作系统的东西,我是一个绝对的初学者。 - Hasini Silva
1个回答

5
switch 语句基本上没问题,但你不需要 pid 变量,因为你没有使用它。
父进程的代码也基本上没问题,但是字符串实际上是 18 个字节,没有 NUL 终止符,带有 NUL 终止符则为 19 个字节。最好在子进程中处理换行和 NUL 终止符,所以我会坚持使用 17 个字节并从字符串中删除换行符。
子进程的代码是错误的。你需要一个变量来存储 read 的返回值。你需要检查返回值以确保 read 成功。而且你需要在字符串中添加 NUL 终止符。在 C 编程语言中,"字符串" 是以零字节(称为 NUL 终止符,写作 '\0')结束的字符数组。你的工作是确保你使用的缓冲区始终足够大以容纳 NUL 终止符,并且每个字符串都有一个 NUL 终止符。
因此,修复后的代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int main( void )
{
    int fd[2];
    char buffer[20];

    if ( pipe(fd) < 0 ) {
        perror( "pipe" );
        exit( 1 );
    }

    switch( fork() ) {
        case -1:
            perror( "fork" );
            exit( 1 );

        case 0:
            /*child process*/
            close(fd[1]);
            ssize_t count = read( fd[0], buffer, sizeof(buffer)-1 );
            if ( count <= 0 ) {
                perror( "read" );
                exit( 1 );
            }
            buffer[count] = '\0';
            printf( "Child read message from parent: %s\n", buffer );
            exit(1);

        default:
            /*parent process*/
            close(fd[0]);
            char *message = "Hello from parent";
            size_t length = strlen( message );
            write( fd[1], message, length );
            break;
    }

    return 0;
}

我最好问一下。我忘记了空终止符。但我有些事情需要澄清。我认为我已经检查了返回值,以确保“read”在开始时成功。如果“(pipe(fd) < 0) { perror("pipe"); exit(1); }” - Hasini Silva
2
@hasinisilva 从pipe的返回值可以判断管道是否成功创建。在正常情况下,如果创建管道成功,则read应该成功。但最好还是检查read的返回值。例如,如果父进程在发送消息之前被SIGSTOPSIGKILL停止,则子进程中的read将失败。 - user3386109
现在我明白了,我误解了那个。无论如何,我很感激你回答了我的问题。我能够澄清许多不确定的点。另一个令人困惑的事情是 'exit(1)'。为什么我们总是使用 '1' 而不是其他数字值。我曾经尝试过使用 0,代码执行时没有任何问题。 - Hasini Silva
1
@hasinisilva 你传递给 exit 的值在程序内部没有影响。但是,如果你从一个 shell 脚本中调用程序,则该值将返回到脚本中。脚本可以根据程序成功或失败来采取不同的操作。通常,exit(0) 表示程序成功,而任何其他值表示程序失败。 - user3386109
1
其实我刚刚才知道这个。我以前使用exit()时并不知道它背后的确切原理。有像@user3386109这样的伟大帮助真是太好了。谢谢! - Hasini Silva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接