在单个管道中进行多次读写
Multiple read and write in a single pipe
我正在尝试理解 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" 然后在第二次读取时调用它阻塞
第二个缓冲区数据发生了什么。丢了吗?
你的readbuffer是30字节,所以这个调用:
read(filedes[0], readbuffer, sizeof(readbuffer));
最多读取 30 个字节。
您正在写入 24 个字节(每个字符串 11 个字符加上 nul 终止符 1 个字节)。 read
将读取所有这些字节。什么都没有丢失。
问题出现在这里:
printf("read:%s\n", readbuffer);
readbuffer 看起来像这样(其中 [=14=]
是 nul 终止符):
hello pipe1[=12=]hello pipe2[=12=]
当 printf 遇到第一个 nul 时,它会将其视为字符串的结尾,因此只会打印 "hello pipe1"。
如果将读取缓冲区大小更改为 sizeof(buffer1)
,这应该会按预期工作(假设两个输出字符串的大小相同)。
第一个 read
实际上消耗了两个 write
的所有数据。第二次调用 read
阻塞,因为它没有找到任何可用数据,正在等待一些数据出现。
为什么 printf()
不显示所有数据?每次调用 write()
都会发送一个空终止符 ([=23=]
)。 printf
的 s
说明符在第一次遇到 null 时停止打印。
要详细了解这一点,请先仔细查看每个缓冲区中的数据:
char buffer1[] = "hello pipe1";
printf("strlen(buffer1): %zu\n", strlen(buffer1));
printf("sizeof(buffer1): %zu\n", sizeof(buffer1));
strlen(buffer1): 11
sizeof(buffer1): 12
缓冲区实际包含:
hello pipe1[=12=]
编译器分配 12 个字节:11 个字节的文本和 1 个字节用于空终止符。
检查 write
的 return 值表明它实际上写入了所有 12 个字节:
ssize_t n_written = write(filedes[1], buffer1, sizeof(buffer1));
printf("Number of bytes written: %zd\n", n_written);
n_written: 12
它这样做是因为 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
是空终止的。这是一个开始:
ssize_t nread = read(filedes[0], readbuffer, sizeof(readbuffer)-1);
if (nread > 0)
readbuffer[nread] = '[=17=]';
请注意 read
的 count
参数正在为空终止符保存 space。
我正在尝试理解 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" 然后在第二次读取时调用它阻塞 第二个缓冲区数据发生了什么。丢了吗?
你的readbuffer是30字节,所以这个调用:
read(filedes[0], readbuffer, sizeof(readbuffer));
最多读取 30 个字节。
您正在写入 24 个字节(每个字符串 11 个字符加上 nul 终止符 1 个字节)。 read
将读取所有这些字节。什么都没有丢失。
问题出现在这里:
printf("read:%s\n", readbuffer);
readbuffer 看起来像这样(其中 [=14=]
是 nul 终止符):
hello pipe1[=12=]hello pipe2[=12=]
当 printf 遇到第一个 nul 时,它会将其视为字符串的结尾,因此只会打印 "hello pipe1"。
如果将读取缓冲区大小更改为 sizeof(buffer1)
,这应该会按预期工作(假设两个输出字符串的大小相同)。
第一个 read
实际上消耗了两个 write
的所有数据。第二次调用 read
阻塞,因为它没有找到任何可用数据,正在等待一些数据出现。
为什么 printf()
不显示所有数据?每次调用 write()
都会发送一个空终止符 ([=23=]
)。 printf
的 s
说明符在第一次遇到 null 时停止打印。
要详细了解这一点,请先仔细查看每个缓冲区中的数据:
char buffer1[] = "hello pipe1";
printf("strlen(buffer1): %zu\n", strlen(buffer1));
printf("sizeof(buffer1): %zu\n", sizeof(buffer1));
strlen(buffer1): 11
sizeof(buffer1): 12
缓冲区实际包含:
hello pipe1[=12=]
编译器分配 12 个字节:11 个字节的文本和 1 个字节用于空终止符。
检查 write
的 return 值表明它实际上写入了所有 12 个字节:
ssize_t n_written = write(filedes[1], buffer1, sizeof(buffer1));
printf("Number of bytes written: %zd\n", n_written);
n_written: 12
它这样做是因为 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
是空终止的。这是一个开始:
ssize_t nread = read(filedes[0], readbuffer, sizeof(readbuffer)-1);
if (nread > 0)
readbuffer[nread] = '[=17=]';
请注意 read
的 count
参数正在为空终止符保存 space。