在单个管道中进行多个读取和写入

时间:2019-07-21 01:50:19

标签: c linux operating-system pipe ipc

我试图了解Linux中的管道。编写了一个基本代码,该代码将尝试两次写入文件描述符的写入末尾,然后执行两次读取。在第二次读取时它被阻止。

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

int main()
{
    int filedes[2];
    char buffer1[] = "hello pipe1";
    char buffer2[] = "hello pipe2";
    char readbuffer[30] = {};

    if (pipe(filedes) == 0) {
        printf("Pipe successful\n");
        printf("read from %d, write to %d\n", filedes[0], filedes[1]);
        write(filedes[1], buffer1, sizeof(buffer1));
        perror("write");
        write(filedes[1], buffer2, sizeof(buffer2));
        perror("write");
        read(filedes[0], readbuffer, sizeof(readbuffer));
        printf("read:%s\n", readbuffer);
        read(filedes[0], readbuffer, sizeof(readbuffer));
        printf("read:%s\n", readbuffer);
        close(filedes[1]);
        close(filedes[0]);
    } else {
        perror("pipe failed");
    }
    return 0;
}

我将输出显示为“ hello pipe1”,然后在第二次读取调用中将其阻塞 第二缓冲区数据发生了什么。迷路了吗?

2 个答案:

答案 0 :(得分:2)

您的读取缓冲区为30个字节,因此调用:

read(filedes[0], readbuffer, sizeof(readbuffer));

最多可读取30个字节。

您正在写入24个字节(每个字符串11个字符,再加上nul终止符一个字节)。 read将读取所有这些字节。一无所有。

问题出现在这里:

printf("read:%s\n", readbuffer);

readbuffer看起来像这样(其中\0是nul终止符):

hello pipe1\0hello pipe2\0

printf击中第一个nul时,会将其视为字符串的结尾,因此仅会打印“ hello pipe1”。

如果将读取缓冲区的大小更改为sizeof(buffer1),这应该可以正常工作(假设两个输出字符串的大小相同)。

答案 1 :(得分:1)

第一个read实际上消耗了两个write的所有数据。对read的第二次调用被阻止,因为它找不到任何可用的数据,正在等待某些数据出现。

为什么printf()不显示所有数据?对write()的每次调用都会发送一个空终止符(\0)。 printf的{​​{1}}说明符在第一次遇到null时便停止打印。

要详细了解这一点,请先仔细查看每个缓冲区中的数据:

s
char buffer1[] = "hello pipe1";
printf("strlen(buffer1): %zu\n", strlen(buffer1));
printf("sizeof(buffer1): %zu\n", sizeof(buffer1));

缓冲区实际上包含:

strlen(buffer1): 11
sizeof(buffer1): 12

编译器分配12个字节:11个字节的文本和1个字节的空终止符。

检查write的返回值表明它实际上写入了所有12个字节:

hello pipe1\0
ssize_t n_written = write(filedes[1], buffer1, sizeof(buffer1));
printf("Number of bytes written: %zd\n", n_written);

之所以这样做是因为n_written: 12 的{​​{1}}参数告诉它:

write

您可以将其更改为仅写入字符串的内容:

count

,但是您需要确保 write(filedes[1], buffer1, sizeof(buffer1)); // ^^^^^^^^^^^^^^^ write the entire buffer, including null 为空终止。像这样的事情是一个开始:

write(filedes[1], buffer1, strlen(buffer1));
//                         ^^^^^^^^^^^^^^^ write only the string's contents,
//                                         excluding null

请注意,readbuffer的{​​{1}}参数为空终止符节省了空间。

相关问题