为什么管道的读端只有在写端关闭时才读取EOF?

10

我不是很理解“关闭管道的写端”和“不向管道写任何内容”之间的区别。如果我不向管道写任何东西,而且管道是空的,那么为什么读取端只是阻塞而不是读取EOF?这与关闭写端有何不同?


6
想象一下电话的情境。即使此刻没有人说话,也不代表他们不会很快开始说话。EOF 就像他们挂断电话。 - RedX
类似问题的好答案部分适用于此问题:https://unix.stackexchange.com/a/499732/123739 - papo
2个回答

17

从管道(或任何地方)读取EOF表示没有更多的输入,并且将来也不会有更多的输入。

如果此刻没有可用的输入,但管道未关闭,则读取器(默认情况下)将阻塞等待输入;如果写入器随后向管道写入数据,则该数据将对读取器可用。 EOF会告诉读取器停止尝试读取更多数据。


1
EOF不是从管道中读取的字面量,而是当所有写端关闭时内核发送给读端的信号? - Xufeng
@Xufeng:没错。EOF是C库中虚构的值,在操作系统中并不存在。 - Zan Lynx
1
@Xufeng:没错。更准确地说,应该称之为文件结束条件。如何指示取决于您从管道中读取的方式。如果使用 fgetc(),它将返回 EOF,这是一个负的 int 值,与任何 unsigned char 值都不同。一些其他函数返回读取的项目数;例如,read() 函数返回 0 表示文件结束。(或错误条件。) - Keith Thompson
+1:请注意,终端(tty和pty设备)在文件打开时可以生成零字节以多次读取。在Unix的read()级别上,如果您在获取零字节后尝试再次读取,则会在下一个数据中继续。在标准I/O级别上,一旦您从文件获取EOF(或错误),则会继续获取它,直到重新定位流(fseek()等)或清除错误(clearerr())。示例代码见下一条评论。(在其中输入文本行;在一行的中间或开头键入Control-D;您需要生成5个EOF消息才能退出。) - Jonathan Leffler
#include <unistd.h> #include <stdio.h> int main(void) { char buffer[4096]; int nbytes; int eof_count = 0; int read_count = 0; while (eof_count < 5) { while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) printf("[%d:%d]<<%.*s>>\n", ++read_count, nbytes, nbytes, buffer); if (nbytes == 0) printf("EOF %d detected\n", ++eof_count); else if (nbytes < 0) { puts("Error detected - exiting"); break; } } puts("All done"); return 0; } - Jonathan Leffler

1

这就是与阻塞文件描述符相关的协议。管道的读端等待数据。关闭它的写端表示数据流结束。这实际上是一个强大的同步概念。

您可以将管道切换到非阻塞模式,其中缺少数据被视为软错误,因此您只需检查是否有任何可读内容。当您需要从多个文件描述符中读取(比如在处理多个客户端的服务器中),这非常有用。这就是IO多路复用发挥作用的地方。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接