tty 所有终端设备的泛称 pty 伪终端 pts 伪终端从属 terminal 终端模拟器
terminal,一个输入输出设备, 在现代os中已经抽象成了控制终端**(controlling terminal), 可以由伪终端,虚拟控制台,串口终端,usb串口担任控制终端**. 它可以
- 传递信号给进程
- 默认为输入输出的通道
- 控制前后台应用的切换
- 标识身份,有些进程需要确认自己在终端运行
[ 系统中有多个 TTY 设备 ]
│
├── /dev/tty1 (虚拟控制台)
├── /dev/pts/0 (伪终端)
├── /dev/pts/1 (另一个伪终端)
├── /dev/ttyS0 (串口)
└── /dev/ttyUSB0 (USB 串口)
│
│ [ 进程创建会话 ]
│
▼
[ 会话关联一个控制终端 ] ← 从上面选一个"任命"
│
│ 例如:任命 /dev/pts/0 为控制终端
▼
[ 该会话的前台进程组 ] ← 能通过这个控制终端接收 Ctrl+C 等信号
控制终端 是一个会话(Session)所关联的终端设备,它是进程接收键盘输入、显示输出、以及接收控制信号(Ctrl+C/Ctrl+Z)的"通道"。
/dev/tty 这个文件是一个"代理",它本身不是控制终端,而是动态指向控制终端的快捷方式。写入 /dev/tty 的数据是直接写入控制终端设备,绕过 stdout 重定向。但如果控制终端是 PTY,数据会进入内核缓冲队列,由读取它的程序(如 bash)决定最终显示位置
进程可以打开任意 TTY 设备读写,但这不改变它的控制终端身份。控制终端在会话生命周期内是固定的,不能像切换文件描述符那样随意更换。:唯一"更换"方式是创建新会话(setsid() + 在新终端启动. 没有控制终端的进程,打开 /dev/tty 会失败。
伪终端是一个虚拟终端,他模仿真实终端与shell交互.为什么要模拟而不是直接交互, 是因为在现代电脑中是使用终端模拟软件交互的, 终端模拟器(xterm/SSH/ttyd)运行在用户空间,无法直接操作物理键盘/屏幕驱动, 但 bash/vim 又期望 isatty() 返回真(是一个真实的物理终端)、能接收 Ctrl+C 信号. 所以内核提供 PTY:Slave 端骗进程,模拟真实终端与进程交互, Master 端让模拟器控制数据流,来模拟用户输入
当打开一个终端时, 终端模拟器会向系统的ptmx申请一对伪终端:master和slave, 他们是一对文件描述符. 然后终端模拟器与master相连接。 Master 端面向用户(终端模拟器),Slave 端面向程序(Shell)。 数据从 Master 写入后,进入内核的 TTY 缓冲队列,由 内核行规程(Line Discipline) 管理。 在规范模式下,行规程负责处理退格、回显,并拦截特殊字符(如 Ctrl+C 生成 SIGINT 信号)。 处理后的数据输入输入缓冲区交给 Slave 端,进程通过读取 Slave 端获取输入。但是一旦确认是 Ctrl+C,行规程不会把 0x03 放入 Slave 的输入缓冲区。 相反,它直接调用内核的信号发送函数(类似于 kill_pgrp()),向该 Slave 终端关联的前台进程组发送 SIGINT 信号。 进程的输出也会写入 Slave 端,经过行规程处理后,由 Master 端 读出并显示给用户
pts还有一种 原始模式(Raw Mode),它们会修改行规程配置,关闭“特殊字符处理”和“回显”。,Ctrl+C 不会被行规程拦截,而是作为一个普通字节 0x03 传给进程
[ 终端模拟器 ] <==读写== [ Master FD ] <==内核缓冲== [ 行规程 (Line Discipline) ] <==读写== [ Slave FD ] <==dup2== [ Bash/Shell ]
^ ^ ^ ^ ^
| | | | |
(显示给用户) (伪终端主端) (核心逻辑处理) (伪终端从端) (实际运行程序)
ttyd的调用过程
1. ttyd 调用 openpty() → 获得 Master/Slave FD
2. fork() 创建子进程
3. 子进程调用 setsid() → 创建新会话
4. 子进程打开 Slave FD(/dev/pts/0)
5. 🔑 内核自动:因为这是会话领导进程首次打开终端 → 将该 Slave 设为控制终端
6. 子进程 dup2(slave_fd, STDIN/OUT) + exec("/bin/bash")
7. 结果:bash 的控制终端 = /dev/pts/0(伪终端 Slave)
ps
可以将伪终端看成是一个中间加了特殊处理程序的管道,就可以想操作pipe那样使用
另外许多程序会检测他的输入输出设备是终端还是管道,比如ls如果他的输出是终端就会正常显示彩色,如果是管道那么他会将颜色符号删去再输入, 比如vim打开时会检查他的输入是否是终端,只有终端才能打开