当我说标准输入时,我指的是 fd = 0 所指的流。
我正在学习一个涵盖 block 和字符设备的操作系统类(class)。它专门说键盘是一个字符设备。然而,当我们看到 read
系统调用时,我们被告知内核不关心它正在读取什么,只要它是 block 设备或 block 设备上的文件即可。
这是我们得到的代码:
#include <stdlib.h>
#include <unistd.h>
const int BUFFSIZE = 5;
int main () {
int fd, n;
char buffer[BUFFSIZE];
int stdin = 0;
int stdout = 1;
int stderr = 2;
do {
n = read (0, buffer, BUFFSIZE);
if (n < 0) {
write (stderr, "Error occurred\n", 10);
} else {
write (stdout, "Entered if\n", 20);
write (stdout, buffer, n);
}
} while (n > 0);
return 0;
}
我的问题是:Linux 如何处理标准输入 (fd = 0)?它是否被视为字符设备,或者内核是否做了某种缓冲(从我运行代码时得到的结果来看,这似乎很可能。)
此外,了解我是否可以使用 read 系统调用来读取一般的字符设备会很有用。如果是,输入是否缓冲?
最佳答案
内核通常很少或根本不对字符设备进行缓冲。
内核在读取文件系统中的文件时会进行一定量的缓冲。
你不能说什么是设备标准输入,因为它因进程而异。默认情况下,fd 0 通常是用户的键盘,它是一个字符设备。但是如果我说
program < file
那么fd 0就是一个普通文件。如果我说
program < /dev/hda0
那么fd 0就是一个 block 设备。如果我努力的话,我也可能设法让 fd 0 连接到网络套接字。
在 Linux 中,还有 /proc/<em>pid</em>/fd/0
,但这也不是设备;它最终看起来像是指向实际设备的符号链接(symbolic link) /dev
,无论它是什么。
附录:特定设备是否被缓冲实际上取决于该设备的驱动程序是如何编写的。任何给定的驱动程序可能会或可能不会实现某种形式的缓冲。此外,缓冲是否实际使用可能最终取决于其他因素。 (例如,Unix 终端驱动程序默认都是行缓冲的,但如果您将驱动程序置于“cbreak”或“raw”模式,则该缓冲将关闭)。我不认为你可以做出任何一般性的陈述来说明字符或 block 设备是否被缓冲。
附录 2:当您开始层层剥离时,它会变得相当复杂。 Unix 努力(通常做得很好)在按我的意思去做和保持简单、愚蠢之间取得适当的平衡。例如,如果您有一个不行缓冲的终端,并且您要求输入 10 个字符,但只有 3 个可用,read()
将返回 3。这是正确的,但它表明某处仍有一个缓冲区,这三个字符在键入时间和阅读时间之间累积。此外,如果您只要求 3 个,但有 10 个可用,在某些情况下,我认为其他 7 个会为您保留,这再次表明相当多的内核级缓冲。
但是在原始模式下,我很确定如果您阅读的速度不够快,您可能会丢失字符。将我们的注意力从终端驱动程序转移到网络套接字上,我认为在某些情况下,如果您执行 read()
在 UDP 模式套接字上,实际的 UDP 数据包比您的读取请求大,您也可能在那里丢失其余的数据包。 [尽管评论者认为我可能是错的。](另一方面,TCP 模式套接字显然有大量缓冲!)
因此,归根结底:规则可能很复杂,准确的细节肯定不仅取决于所使用的特定设备驱动程序,还可能取决于无数其他细节。
关于c - stdin 在 Linux 中是否被视为字符设备?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36559689/