在 Linux 中,终端与 Shell 相关联。终端将输入发送到 Shell(例如:pwd
),而 Shell 将输出发送回终端(例如:/home/paul
)。
下图展示了 Terminal 和 Shell 之间的关系(假设我使用的 Terminal 是gnome-terminal
,Shell 是bash
):
现在我想知道的是终端和Shell使用什么机制来交换数据。这就是我认为发生的情况:
- 执行时
gnome-terminal
,会在目录中创建一个代表串口的文件/dev/pts
(假设文件名为/dev/pts/0
)。 gnome-terminal
然后将执行与其关联的 Shell(例如:bash
),并向其传递 pts 文件名(例如,可以通过命令行参数传递 pts 文件名)。- 现在 和 都
gnome-terminal
将从bash
开始读取/dev/pts/0
。 - 当
gnome-terminal
要发送数据时bash
,它会写入该数据/dev/pts/0
,并bash
从中读取该数据/dev/pts/0
。 - 当
bash
要发送数据时gnome-terminal
,它会写入该数据/dev/pts/0
,and
gnome-terminal
并从中读取该数据/dev/pts/0
。
该图显示了我刚刚解释的内容:
我的理解正确吗?
笔记:当然,如果我们使用虚拟终端(即,当我们不使用 GUI 时),pts 文件可以是 tty 文件,但逻辑仍然是相同的。
答案1
你缺少了一个必要的部分。伪 tty 设备不像套接字那样对称。有主端和从端。中的文件/dev/pts
代表从设备。
终端模拟器通过调用创建一个伪 tty openpty
(或者对于您想要在新 tty 上运行新进程的常见情况加上一些额外的设置)forkpty
。openpty
在较低级别,这涉及打开/dev/ptmx
并执行一些魔法 ioctl。
调用终端仿真器的结果是得到一对文件描述符,并且还可以得到slave对应的openpty
文件名。/dev/pts
主进程没有单独的名称,因为子进程不需要按名称打开它。
主设备和从设备的行为有点像套接字的两端:您在一端写入的内容将从另一端读取。但因为这是一个 tty,所以所有 tty 模式都会应用于途中的数据。
例如,如果您是终端仿真器,并且收到按键操作A,则应该写入'a'
主文件描述符。这直接相当于通过串行线路从终端将该字节发送到计算机。它将导致'a'
从从机读取(通过任何正在读取它的程序 - 例如 shell)。
D如果在按键按下时收到Ctrl按键按下,则应将一个4
字节 ( 'D' ^ 0x40
) 写入主文件描述符。 (因为这是真正的终端在线路上发送的内容。)接下来发生的情况取决于 tty 模式。在原始模式下,读取从属 tty 的程序将看到一个4
字节。在cooked模式下,tty将激活“EOF特殊键按下”行为。
在相反的方向上,也有一些处理。当某些程序写入'\n'
从属 tty 时,"\r\n"
由于onlcr
后处理,您可能会在主文件描述符上收到。
历史部分,无聊可以跳过
很久以前,从设备的名称如下/dev/ttyp0
,每个设备都有一个相应的主设备,例如/dev/ptyp0
。它们不是动态创建的。终端仿真器可以探测所有这些,找到当前未使用的一个,然后开始使用它。管理所有权和权限是一个问题。xterm
setuid-root 只是为了可以 chown 奴隶。
新方案称为“UNIX98 ptys”,通过神奇的 ioctl 处理设备创建和所有权,因此文件仅在/dev/pts
使用时出现,并且由运行创建它们的程序的用户拥有。