据我所知,/dev/pts
文件是为 ssh 或 telnet 会话创建的。
答案1
中没有存储任何内容/dev/pts
。该文件系统纯粹存在于内存中。
条目/dev/pts
是伪终端(简称pty)。 Unix 内核有一个通用概念终端。终端为应用程序提供了一种通过终端显示输出和接收输入的方法。终端设备。一个进程可能有一个控制终端— 对于文本模式应用程序,这就是它与用户交互的方式。
终端可以是硬件终端(“tty”,“teletype”的缩写)或伪终端(“pty”)。硬件终端通过某些接口连接,例如串行端口 ( ttyS0
, …) 或 USB ( ttyUSB0
, …) 或通过 PC 屏幕和键盘 ( tty1
, …)。伪终端由终端仿真器提供,它是一个应用程序。一些类型的伪终端是:
- GUI 应用程序(例如 xterm、gnome-terminal、konsole 等)将键盘和鼠标事件转换为文本输入并以某种字体以图形方式显示输出。
- 多路复用器应用程序(例如 screen 和 tmux)中继来自另一个终端的输入和输出,以将文本模式应用程序与实际终端解耦。
- 远程 shell 应用程序(例如 sshd、telnetd、rlogind 等)在客户端上的远程终端和服务器上的 pty 之间中继输入和输出。
如果程序打开终端进行写入,则该程序的输出将显示在终端上。多个程序同时输出到终端是很常见的,尽管这有时会令人困惑,因为无法区分输出的哪一部分来自哪个程序。尝试写入其控制终端的后台进程可能是由 SIGTTOU 信号自动暂停。
如果程序打开终端进行读取,则用户的输入将传递到该程序。如果多个程序从同一终端读取,则每个字符将独立路由到其中一个程序;不建议这样做。通常,在给定时间只有一个程序主动从终端读取数据;当程序不在控制终端中时尝试从控制终端读取数据前景是由 SIGTTIN 信号自动暂停。
要进行实验,请tty
在终端中运行以查看终端设备是什么。假设它是/dev/pts/42
.在另一个终端的 shell 中,运行echo hello >/dev/pts/42
:该字符串hello
将显示在另一个终端上。现在运行cat /dev/pts/42
并在另一个终端中输入。要终止该cat
命令(这将使另一个终端难以使用),请按Ctrl+ C。
写入另一个终端有时对于显示通知很有用;例如write
命令就是这样做的。通常不会从另一个终端读取数据。
答案2
中的文件/dev/pts
是“pseudo-ttys”。它们在某种程度上类似于命名管道,但它们也模仿旧的串行连接终端,例如 VT-100。伪 tty 负责将字节从键盘传输到程序,以及从程序传输到输出设备,这听起来很简单。但这回答了您明确的问题:/dev/pts/0
例如,内核不存储任何内容。只有来自连接到伪 tty 的程序的 stdout 的字节流才会进入,并且 stdin 连接到同一伪 tty 的程序会读取这些字节。
伪 tty 还在这些字节流中放置了一个间接层。内核可以检查字节中的特殊值,例如“Control-C”或“Control-D”或“Control-U”(这些都是可配置的,请参阅 参考资料man stty
)并发送 SIGINT、在 stdin 上设置文件结尾或擦除输入上的一行。那里还有一个缓冲功能,所以我的“不存储任何内容”有点错误,但只有几千字节。
内核可以检查输出上的字节值,并执行诸如将换行符(ASCII 换行符、LF 或"\n"
)转换为两个字节、回车符和换行符(CRLF 或"\r\n"
)或串行终端硬件所需的任何字节之类的操作。伪终端的间接性允许独立于硬件。
伪 tty 还允许所有“设置波特率”、“设置奇偶校验”等ioctl()
系统调用,并且可能对它们不执行任何操作。这使得在 VT-100、ADM-3 和 Wyse 时代编写的程序能够继续运行而不会出错。软件(伪 ttys 设备驱动程序)的作用类似于硬件。
伪 tty 可以由sshd
和使用telnet
,但它们也可以在终端仿真器(如xterm
或rxvt
)和通常在 xterm 内运行的 shell 之间使用。
Linux 和许多 Unix 有伪 tty。计划9则不然。伪 tty 有点像遗迹,是串行电缆连接硬件终端时代遗留下来的。
答案3
/dev/
是设备文件的特殊目录。这些是抽象的,它们不是磁盘上的真实文件。该目录在启动时填充,并且可能会发生更改以反映现有的设备接口,这些接口由内核和用户空间守护程序创建和销毁udevd
。
如此表示的许多设备都是虚拟的。这包括 中的条目/dev/pts
,它们是控制台设备。这就是为什么要为远程会话创建一个会话;当您打开本地 GUI 终端时也会创建它们。
您可以将它们作为文件打开,尽管它没有多大用处。要获取/dev/pts
shell 连接的节点,请使用tty
:
> tty
/dev/pts/4
现在切换到其他控制台并尝试:
> echo "duck!" > /dev/pts/4
聪明的。现在尝试:
> cat /dev/pts/4
然后尝试使用 /dev/pts/4 处的 shell。你会被困住,直到你退出cat
另一边,但你在 pts/4 上输入的大部分内容都会通过(例如尝试“hello world”,我最终在hl
pts/4 和控制台ello word
上输入cat
)。
我的猜测是,设备正在从 shell 获取输入,并通过系统输出它,这就是内容最终出现在屏幕上的方式——shell 不处理硬件,而是系统。尝试(如果你不知道它是什么,strace bash
请看一下);man strace
当 bash 启动时,你会收到一连串的呼叫。现在开始敲击按键:
read(0, "h", 1) = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "h", 1h) = 1
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, "e", 1) = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "e", 1e) = 1
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, "y", 1) = 1
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "y", 1y) = 1
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
对于输入的每个字母,都会从标准输入读取并写入标准输出。但是 shell 的标准输出连接到什么?现在尝试strace
在你的 GUI 终端上——如果你不知道它的名字,你就必须找出它的名字,例如在 KDE 上它是konsole
,我相信 GNOME 上有gnome-terminal
。其输出strace
可能更加神秘——我的输出有很多poll()
和recvfrom()
。我没有看到任何写入,但是如果您现在cat
从另一个终端中提取技巧,您会注意到当您键入时, cat 读取的击键导致 strace 输出中根本没有响应 - 终端是'没有收到它们。因此,GUI 终端应用程序和 cat 竞争从 shell 输出到的同一设备进行读取。