【问题标题】:How to work with two pipes while sending data between child and parent process?在子进程和父进程之间发送数据时如何使用两个管道?
【发布时间】:2020-01-06 15:59:59
【问题描述】:

我正在学习系统调用、fork 和 pipe。我正在创建一个 C 程序,其中父进程向子进程发送一个字符数组,子进程将数组的前 4 个字符大写并将其发回。数组从父进程正确发送到子进程,子进程进行转换,甚至正确写入第二个管道,但父进程无法从管道 2 读取新数组。

我也尝试关闭不必要的描述符,但没有奏效。我在某处读到父进程可能在从管道读取内容之前完成,为此我尝试了等待功能(但我可能做错了。我不确定。)

我尝试检查进程发送和接收的值的大小,

父母写 (8)

儿童阅读 (8)

孩子写 (8)

父读(1)

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

int main(int argc, char *argv[]){
    int pipe1[2];
    int pipe2[2];
    char str[8], str1[8];
    pid_t pid;

    if(pipe(pipe1) < 0){
        perror("Pipe 1 not created\n");
        exit(EXIT_FAILURE);
    }

    if(pipe(pipe2) < 0){
        perror("Pipe 2 not created\n");
        exit(EXIT_FAILURE);
    } 

    pid = fork();

    if (pid == 0){
        close(pipe1[1]);
        close(pipe2[0]);
        printf("\nChild Process");
        ssize_t rd_stat_child = read(pipe1[0], str, 8*sizeof(char));
        if(rd_stat_child > 0){
            printf("rc%zd\n", rd_stat_child);
            for(int i = 0; i < 4; i++){
                str[i] = ((char)(((int)str[i])-32));
            }

            printf("\nFinal str in child: %s\n", str);
            ssize_t wr_stat_child = write(pipe2[1], str, 8*sizeof(char));
            printf("wc%zd\n", wr_stat_child);
            if(wr_stat_child != sizeof(str)){
                perror("Sending to parent failed");
                exit(EXIT_FAILURE);
            }
        }else{
            perror("Child failed to read");
            exit(EXIT_FAILURE);
        }

    }else if (pid > 0){
        close(pipe1[0]);
        close(pipe2[1]);
        printf("\nParent Process");
        printf("\nEnter a 8 character string: ");
        scanf("%s", str);
        if(sizeof(str)/(8*sizeof(char)) != 1){
            perror("Size of string greater than 8\n");
            exit(EXIT_FAILURE);
        }else{
            ssize_t wr_stat_parent = write(pipe1[1], str, 8*sizeof(char));
            printf("wp%zd\n", wr_stat_parent);
            if(wr_stat_parent != sizeof(str)){
                perror("Parent failed writing.\n");
                exit(EXIT_FAILURE);
            }
            ssize_t rd_stat_parent = read(pipe2[0], str, 8*sizeof(char));
            close(pipe2[0]);
            if(rd_stat_parent <= sizeof(str)){
                printf("rp%zd\n", rd_stat_parent);
                printf("\nParent Recieved\n %s", str);
            }else{
                perror("Parent error while reading\n");
                exit(EXIT_FAILURE);
            }

        }
    }

    return 0;
}

预期输出

父进程 (输入)>> lkybzqgv

子进程 (进程) >> LKYBzqgv

父进程 (输出)>> LKYBzqgv

实际输出

父进程 (输入)>> lkybzqgv

子进程 (进程) >> LKYBzqgv

父进程 (输出)>> kybzqgv

【问题讨论】:

  • 仅仅因为您一次将 N 个字节写入管道或流套接字的一端并不意味着您将在另一端一次读取 N 个字节。
  • 但是为什么它在子进程的情况下起作用,而在父进程的情况下呢?那我该怎么做呢?
  • 越界写入的未定义行为。
  • 你能解释一下你的意思吗?
  • 不是问题,但sizeof(str) 告诉您缓冲区大小,而不是内容长度,无论如何您需要 9 个字符来存储以零结尾的 8 个字母字符串。 strlen(str)/(8*sizeof(char)) 是整数数学,不会做你认为它会做的事!

标签: c kernel pipe fork system-calls


【解决方案1】:

您的字符串处理已损坏。您需要一个长度为 9 的数组来保存长度为 8 的字符串。(请记住,c 中的字符串以零结尾)。 不要写scanf("%s", str); 来读取字符串!!这和使用gets() 一样糟糕。它允许您溢出缓冲区(这实际上发生在您的情况下)。像这样读取字符串:

scanf("%8s", str);

这将读取最多 8 个(非空白)字符并将它们与零终止符一起存储在 str 中。 (再次记住 str 必须足够大以容纳 8 个字符 + 1 个终止字符)

然后检查字符串的长度,使用strlen(),不要使用sizeof()sizeof 可能只告诉保存字符串的数组的大小,或者指向字符串的指针。请记住,保存字符串的数组必须至少比字符串大 1 个字符,但允许大于该值。并且数组的大小在创建时是固定的。它不会根据您放入的内容而改变大小。

哦,顺便说一句。您不发送/接收终止字符,因此您必须在调用 read() 后自己手动设置:

read(pipe1[0], str, 8);
str[8] = 0;

您的代码可能存在其他问题,但除非您修复字符串问题,否则您的行为未定义,其他一切都无关紧要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-27
    • 2011-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多