今天早上5点,我读了一篇关于read
系统调用的文章。事情对我来说变得非常清楚。
ssize_t read(整数fd,void*buf,大小计数);
类似于cc>的操作系统的构建变得非常简单。对于任何实体的文件接口,只需通过指针从这个*nix
接口将一些日期写入内存。网络,文件,流都一样。
但有个问题出现了。
如何区分两种情况?:
1)流为空需要等待新数据。2)流关闭需要关闭程序。
下面是一个场景:
在循环中从fd
读取数据时,这个*buf
被STDIN
重定向。
一些STDIN
出现
只是一点一点地读,直到记忆中有什么东西,或者是因为呼叫而有什么东西?
程序将如何理解:等待新的输入,还是退出?
这还不清楚。在pipe
或text_data
流的情况下。
在与@Bailey Kocin交谈并阅读了一些文档后,我有了这种理解。如果我错了就帮我。EOF
保持程序执行并等待0
比特数。
当read
出现比特数时endless
将其写入continuous
并继续执行。
当read
关闭时count
返回count
,这是程序可能完成的信号。
问题是read
是否出现在buf
中?
UPD2stream
是一个常数,可以在read
函数的输出中
while (ch != EOF) {
/* display contents of file on screen */
putchar(ch);
ch = getc(fp);
}
但在
0
的情况下,EOF
值不出现在abuf
中。EOF
系统调用通过返回getc
通知文件结束。而不是将read
常数写入EOF
,就像ak在buf
的情况下一样。read
是在不同系统中变化的常数。用于0
。
最佳答案
我们先来处理你原来的问题。注意man 7 pipe
应该提供一些有用的信息。
假设我们将标准输入重定向到由pipe
调用创建的描述符的输入端,如:
pipe(p);
// ... fork a child to write to the output side of the pipe ...
dup2(p[0], 0); // redirect standard input to input side
我们称之为:
bytes = read(0, buf, 100);
首先,请注意,这种行为与直接从
p[0]
中读取没有什么不同,因此我们可以这样做:pipe(p);
// fork child
bytes = read(p[0], buf, 100);
那么,基本上有三种情况:
如果管道中有字节(即至少一个字节已经被写入,但尚未读取),那么读取调用将立即返回,并且它将返回最多可达100字节的所有可用字节。返回值将是读取的字节数,并且始终是介于1和100之间的正数。
如果管道为空(没有字节),并且输出端已关闭,则不会触及缓冲区,调用将立即返回,返回值为0。
否则,read调用将被阻塞,直到某些内容写入管道或关闭输出端,然后read调用将立即使用案例1和案例2中的规则返回。
因此,如果
read()
调用返回0,则表示已到达文件结尾,并且不需要更多字节。等待额外的数据会自动发生,在等待之后,您将获得数据(正返回值)或文件结束信号(零返回值)。在另一个进程写入一些字节,然后立即关闭(输出端)管道的特殊情况下,下一个read()
调用将返回一个正值,直到指定的count
。后续的read()
调用将继续返回正值,只要有更多的数据要读取。当数据耗尽时,read()
调用将返回0(因为管道已关闭)。在Linux上,对于管道和任何阳性的
count
,以上都是正确的。除了管道,其他东西也可能有区别。此外,如果count
为0,read()
调用将始终立即返回,返回值为0。注意,如果您试图编写在Linux以外的平台上运行的代码,您可能需要更加小心。允许一个实现返回一个非零的字节数小于请求的字节数,即使管道中有更多的字节可用——这可能意味着存在一个实现定义的限制(因此无论您请求多少字节,都不会得到超过4096字节的结果,例如)或者这个实现定义了从一个调用到另一个调用的限制(因此,如果您在内核缓冲区的页面边界上请求字节,那么您只能得到页面的结尾或其他内容)。在Linux上,没有限制——无论count
有多大,read调用总是返回count
之前可用的所有内容。不管怎样,这样的想法是,类似于以下代码的东西应该可靠地从管道读取所有字节,直到关闭输出端,即使在Linux以外的平台上也是如此:
#define _GNU_SOURCE 1
#include <errno.h>
#include <unistd.h>
/* ... */
while ((count = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)))) > 0) {
// process "count" bytes in "buffer"
}
if (count == -1) {
// handle error
}
// otherwise, end of data reached
如果管道从未关闭(“无尽”或“连续”流),
while
循环将永远运行,因为read
将阻塞,直到它可以返回非零字节计数。请注意,管道也可以设置为非阻塞模式,这会实质性地改变行为,但以上是默认的阻塞模式行为。
关于你的UPD问题:
是的,
read
保持程序执行直到数据可用,但是不,它不一定等待count
字节。它将等待至少一个非空的write
到管道,这将唤醒进程;当进程有机会运行时,它将返回所有可用的字节,但不一定等于count
字节。通常,这意味着如果另一个进程写入5个字节,阻塞的read(fd, buffer, 100)
调用将返回5并继续执行。是的,如果read
返回0
,则表示不再有要读取的数据,并且管道的写入端已关闭(因此不再有可用的数据)。不,缓冲区中不显示EOF
值。只有读取的字节才会出现在那里,并且当read()
返回0时不会触及缓冲区,因此它将包含read()
调用之前的所有内容。关于您的UPD2评论:
是的,在Linux上,EOF是一个常数,等于整数
-1
。(从技术上讲,根据C99标准,它是一个等于负值的整数常量;也许有人知道它不是-1
的平台)这个常量不被read()
接口使用,而且肯定不会写入缓冲区。如果出现错误,read()
返回-1,那么将read()
的返回值与EOF(而不是-1)进行比较将被认为是不好的做法。正如您所注意到的,EOF值实际上只用于C库函数,如getc()
和getchar()
来区分文件结尾和成功读取的字符。
关于c - Linux中STREAMS的魔力。什么时候结束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56406603/