从管道读取时数据丢失

问题描述 投票:0回答:2

我正在学习Linux编程。这是我的代码。我想在子进程中写入并从父进程中读取。似乎有些数据丢失了。我的代码有什么问题吗?

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


int main(int argc, char* argv[]) {
    pid_t pid;

    char buf[1024];

    int link[2];
    pipe(link);

    pid = fork();

    if (pid < 0) {
        printf("fork failed\n");
        return -1;
    } else if(pid == 0) { //child process
        //
        char buf_child[256];
        //dup2(link[1], STDOUT_FILENO);
        close(link[0]);
        //close(link[1]);
        int i;
        for(i = 0; i < 10; ++i){
            sprintf(buf_child,"current number is : %d", i);
            write(link[1], buf_child, sizeof(buf_child));
            //sleep(1);
        }
        printf("[child process] now close pipe write end\n");
        close(link[1]);
        printf("child process exit...\n");
        exit(0);
    } else {//parent process
        //
        close(link[1]);
        int nbytes;
        while(1) {
            printf("[parent process] start read...\n");
            nbytes = read(link[0], buf, sizeof(buf));
            if(nbytes == -1) {
                printf("read failed, reason: %s\n", strerror(errno));
                break;
            } else if(nbytes != 0){
                printf("data: %.*s\n", nbytes, buf);
            } else {
                printf("parent process: finish read from pipe\n");
                break;
            }

        }
        wait(NULL);
    }

    return 0;
}

输出:

[parent process] start read...
data: current number is : 0
[parent process] start read...
data: current number is : 4
[parent process] start read...
data: current number is : 8
[parent process] start read...
[child process] now close pipe write end
child process exit...
parent process: finish read from pipe

添加sleep语句后,所有数据都可以从父进程读取。

c linux pipe
2个回答
0
投票

没有数据丢失,您的父进程一次读取 1024 字节,而子进程一次写入 256 字节的缓冲区。父级每次执行

read()
操作时,您都会读取子循环最多 4 次迭代的数据。由于字符串以 NUL 结尾,因此每次打印时,您只会看到第一个字符串,因为
printf
将在第一个终止符处停止打印。

您必须将父级的缓冲区大小更改为

256
或使用不同的机制来读取数据,例如一次读取一个字节,直到看到 NUL
\0
字节。后者会更加稳健。您也可以只写入字符串的长度(由
sprintf
返回)。


0
投票

您收到

"current number is : 0\x00??..??current number is : 1\x00??..??curren..."

其中

??..??
代表 235 个未知字符。

然后打印到第一个 NUL。

© www.soinside.com 2019 - 2024. All rights reserved.