我试图了解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”,然后在第二次读取调用中将其阻塞 第二缓冲区数据发生了什么。迷路了吗?
答案 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}}参数为空终止符节省了空间。