stdin 在 Linux 中是否被视为字符设备?

Rad*_*asz 1 c linux io operating-system input-devices

当我说 stdin 时,我指的是 fd = 0所指的

我正在学习一门涵盖块设备和字符设备的操作系统课程。具体说键盘是字符设备。然而,当我们看到read系统调用时,我们被告知内核并不关心它正在读取什么,只要它是块设备或块设备上的文件。

这是我们得到的代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:Linux 如何处理标准输入 (fd = 0)?它是否被视为字符设备,或者内核是否进行了某种缓冲(根据我在运行代码时得到的结果来判断,这似乎很可能。)

此外,了解我是否可以使用 read 系统调用来读取一般字符设备会很有用。如果是这样,输入是否被缓冲?

Ste*_*mit 5

内核通常在字符设备上做很少或不做缓冲。

从文件系统中的文件读取时,内核会进行一定量的缓冲。

你不能说设备标准输入是什么样的,因为它因进程而异。默认情况下,fd 0 通常是用户的键盘,它是一个字符设备。但如果我说

program < file
Run Code Online (Sandbox Code Playgroud)

那么 fd 0 是一个普通文件。如果我说

program < /dev/hda0
Run Code Online (Sandbox Code Playgroud)

那么 fd 0 是一个块设备。如果我在那里工作,我也可能设法将 fd 0 连接到网络套接字。

在 Linux 中,也有,但这也不是设备;它最终看起来像是 中实际设备的符号链接,无论它是什么。/proc/pid/fd/0/dev


附录:特定设备是否被缓冲实际上取决于该设备的驱动程序是如何编写的。任何给定的驱动程序可能会或可能不会实现某种形式的缓冲。此外,是否实际使用缓冲可能最终取决于其他因素。(例如,Unix 终端驱动程序在默认情况下都是行缓冲的,但如果您将驱动程序置于“cbreak”或“raw”模式,则该缓冲将关闭)。我认为您不能做出任何一般性的陈述来说明字符或块设备是否被缓冲。


附录 2:当您开始剥离层时,它会变得非常复杂。Unix 非常努力(并且通常做得非常好)在做我的意思和保持简单,愚蠢之间取得适当的平衡。例如,如果您有一个没有行缓冲的终端,并且您要求输入 10 个字符,但只有 3 个可用,read()则将返回 3。这是正确的,但它表明某处仍然存在缓冲区,这三个字符在它们被输入和你阅读它们的时间之间累积的地方。此外,如果您只要求 3 个,但有 10 个可用,在某些情况下,我认为其他 7 个会为您保存,再次表明相当数量的内核级缓冲。

但是在原始模式下,我很确定如果您阅读速度不够快,您可能会丢失字符。将我们的注意力从终端驱动程序转移到网络套接字,我认为在某些情况下,如果您read()在 UDP 模式套接字上执行一个操作,而实际的 UDP 数据包大于您的读取请求,您可能会在那里丢失其余的数据包, 也。[尽管评论者暗示我可能错了。](另一方面,TCP 模式套接字显然被大量缓冲!)

所以,底线是:规则可能很复杂,精确的细节肯定不仅取决于所使用的特定设备驱动程序,还取决于潜在的无数其他细节。