首页 » SEO优化 » php伪终端技巧_理解 Linux 终端终端模拟器和伪终端

php伪终端技巧_理解 Linux 终端终端模拟器和伪终端

访客 2024-11-27 0

扫一扫用手机浏览

文章目录 [+]

Teleprinter 也可以写成 teletypewriter 或 teletype 。

后来人们将 Teleprinter 连接到早期的大型打算机上,作为输入和输出设备,将输入的数据发送到打算机,并打印出相应。

php伪终端技巧_理解 Linux 终端终端模拟器和伪终端

在本日你很难想象程序的运行结果须要等到打印出来才能看到, Teleprinter 设备已经进了打算机博物馆。
现在我们用 TTY 代表打算机终端( terminal ),只是沿用了历史习气,电传打字机( teletypewriter )曾经是打算机的终端,它的缩写便是 TTY ( T ele TY pewriter)。

php伪终端技巧_理解 Linux 终端终端模拟器和伪终端
(图片来自网络侵删)

为了把不同型号的电传打字机接入打算机,须要在操作系统内核安装驱动,为上层运用屏蔽所有的低层细节。

电传打字机通过两根电缆连接:一根用于向打算机发送指令,一根用于吸收打算机的输出。
这两根电缆插入 UART (Universal Asynchronous Receiver and Transmitter,通用异步吸收和发送器)的串行接口连接到打算机。

操作系统包含一个 UART 驱动程序,管理字节的物理传输,包括奇偶校验和流量掌握。
然后输入的字符序列被通报给 TTY 驱动,该驱动包含一个 line discipline 。

line discipline卖力转换分外字符(如退格、擦除字、清空行),并将收到的内容回传给电传打字机,以便用户可以看到输入的内容。
line discipline 还卖力对字符进行缓冲,当按下回车键时,缓冲的数据被通报给与 TTY 干系的前台用户进程。
用户可以并行的实行几个进程,但每次只与一个进程交互,其他进程在后台事情。

终端仿照器(terminal emulator)

本日电传打字机已经进了博物馆,但 Linux/Unix 仍旧保留了当初 TTY 驱动和 line discipline 的设计和功能。
终端不再是一个须要通过 UART 连接到打算机上物理设备。
终端成为内核的一个模块,它可以直接向 TTY 驱动发送字符,并从 TTY 驱动读取相应然后打印到屏幕上。
也便是说,用内核模块仿照物理终端设备,因此被称为 终端仿照器 (terminal emulator)。

上图是一个范例的 Linux 桌面系统。
终端仿照器就像过去的物理终端一样,它监听来自键盘的事宜将其发送到 TTY 驱动,并从 TTY 驱动读取相应,通过显卡驱动将结果渲染到显示器上。
TTY 驱动 和 line discipline 的行为与原来一样,但不再有 UART 和 物理终端参与。

如何看到一个终端仿照器呢?在 Ubuntu 20 桌面系统上,按 Ctrl+Alt+F3 就会得到一个由内核仿照的 TTY。
Linux 上这种仿照的文本终端也被称为 虚拟终端(Virtual consoles) 。
每个虚拟终端都由一个分外的设备文件 /dev/tty[n] 所表示,与这个虚拟终真个交互,是通过对这个设备文件的读写操作,以及利用 ioctl 系统调用操作这个设备文件进行的。
通过实行 tty 命令可以查看代表当前虚拟终真个设备文件:

$ tty/dev/tty3

复制代码

可以看到,当前终真个设备文件是 /dev/tty3 ,也便是通过 Ctrl+Alt+F3 得到的虚拟终端。

你可以通过 Ctrl+Alt+F3 到 Ctrl+Alt+F6 在几个虚拟终端之间切换。
按 Ctrl+Alt+F2 回到桌面环境。
X 系统也是运行在一个终端仿照器上,在 Ubuntu 20 上它对应的设备是 /dev/tty2 ,这也是为什么利用 Ctrl+Alt+F2 可以切换到 X 系统的缘故原由。

我们可以看看 X 系统打开的文件中是否包含了设备文件 /dev/tty2 。
先查找 X 系统的 PID:

# ps aux | grep Xorgmazhen 1404 0.1 0.6 741884 49996 tty2 Sl+ 08:07 0:13 /usr/lib/xorg/Xorg vt2 -displayfd 3 -auth /run/user/1000/gdm/Xauthority -background none -noreset -keeptty -verbose 3

复制代码

再看看这个进程(1404)打开了哪些文件:

# ll /proc/1404/fd总用量 0dr-x------ 2 mazhen mazhen 0 7月 10 08:07 ./dr-xr-xr-x 9 mazhen mazhen 0 7月 10 08:07 ../lrwx------ 1 mazhen mazhen 64 7月 10 08:07 0 -> /dev/tty2lrwx------ 1 mazhen mazhen 64 7月 10 08:07 1 -> 'socket:[39965]'lrwx------ 1 mazhen mazhen 64 7月 10 10:09 10 -> 'socket:[34615]'...

复制代码

可以看到,X 系统确实打开了 /dev/tty2 。

再做一个有趣的实验,在 tty3 下以 root 用户身份实行 echo 命令:

# echo "hello from tty3" > /dev/tty4

复制代码

再按 Ctrl+Alt+F4 切换到 tty4,能看到从 tty3 发送来的信息。

伪终端(pseudo terminal, PTY)

终端仿照器(terminal emulator)是运行在内核的模块,我们也可以让终端仿照程序运行在用户区。
运行在用户区的终端仿照程序,就被称为 伪终端(pseudo terminal, PTY) 。

PTY 运行在用户区,更加安全和灵巧,同时仍旧保留了 TTY 驱动和 line discipline 的功能。
常用的伪终端有 xterm,gnome-terminal,以及远程终端 ssh。
我们以 Ubuntu 桌面版供应的 gnome-terminal 为例,先容伪终端如何与 TTY 驱动交互。

PTY 是通过打开分外的设备文件 /dev/ptmx 创建,由一对双向的字符设备构成,称为 PTY master 和 PYT slave 。

gnome-terminal 持有 PTY master 的文件描述符 /dev/ptmx 。
gnome-terminal 卖力监听键盘事宜,通过 PTY master 吸收或发送字符到 PYT slave ,还会在屏幕上绘制来自 PTY master 的字符输出。

gnome-terminal 会 fork 一个 shell 子进程,并让 shell 持有 PYT slave 的设备文件 /dev/pts/[n] ,shell 通过 PYT slave 吸收字符,并输出处理结果。

PTY master 和 PYT slave 之间是 TTY 驱动,会在 master 和 slave 之间复制数据,并进行会话管理和供应 line discipline 功能。

在 gnome-terminal 中实行 tty 命令,可以看到代表 PYT slave 的设备文件:

$ tty/dev/pts/0

复制代码

实行 ps -l 命令,也可以确认 shell 关联的伪终端是 pts/0 :

$ ps -lF S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD0 S 1000 1842 1832 0 80 0 - 3423 do_wai pts/0 00:00:00 bash0 R 1000 1897 1842 0 80 0 - 3626 - pts/0 00:00:00 ps

复制代码

把稳到 TTY 这一列指出了当提高程的终端是 pts/0 。

我们以实际的例子,看看在 terminal 实行一个命令的全过程。

我们在桌面启动终端程序 gnome-terminal ,它向操作系统要求一个 PTY master ,并把 GUI 绘制在显示器上gnome-terminal 启动子进程 bashbash 的标准输入、标准输出和标准缺点都设置为 PYT slavegnome-terminal 监听键盘事宜,并将输入的字符发送到 PTY masterline discipline收到字符,进行缓冲。
只有当你按下回车键时,它才会把缓冲的字符复制到 PYT slave 。
line discipline在吸收到字符的同时,也会把字符写回给 PTY master 。
gnome-terminal 只会在屏幕上显示来自 PTY master 的东西。
因此, line discipline 须要回传字符,以便让你看到你刚刚输入的内容。
当你按下回车键时,TTY 驱动卖力将缓冲的数据复制到 PYT slavebash 从标准输入读取输入的字符(例如 ls -l )。
把稳,bash 在启动时已经将标准输入被设置为了 PYT slavebash 阐明从输入读取的字符,创造须要运行 lsbash fork 出 ls 进程。
bash fork 出的进程拥有和 bash 相同的标准输入、标准输出和标准缺点,也便是 PYT slavels 运行,结果打印到标准输出,也便是 PYT slaveTTY 驱动将字符复制到 PTY mastergnome-terminal 循环从 PTY master 读取字节,绘制到用户界面上。
Shell

我们常常不去区分 terminal 和 Shell,会说打开一个 terminal,或打开一个 Shell。
从前面先容的命令实行过程可以看出,Shell 不处理键盘事宜,也不卖力字符的显示,这是 terminal 要为它处理好的。

Shell 是用户空间的运用程序,常日由 terminal fork 出来,是 terminal 的子进程。
Shell 用来提示用户输入,阐明用户输入的字符,然后处理来自底层操作系统的输出。

常日我们利用较多的 shell 有 Bash、Zsh 和 sh。

配置 TTY 设备

内核将利用 TTY 驱动来处理 terminal 和 Shell 之间的通信。
line discipline 是 TTY 驱动的一个逻辑组件。
line discipline 紧张有以下功能:

当用户输入时,字符会被回传到 PTY masterline discipline会在内存中缓冲这些字符。
当用户按回车键时,它才将这些字符发送到 PYT slaveline discipline可以拦截处理一些分外的功能键,例如:当用户按 CTRL+c 时,它向连接到 PYT slave 的进程发送 kill -2(SIGINT) 旗子暗记当用户按 CTRL+w 时,它删除用户输入的末了一个字当用户按 CTRL+z 时,它向连接到 PYT slave 的进程发送 kill -STOP 旗子暗记当用户按退格键时,它从缓冲区中删除该字符,并向 PTY master 发送删除末了一个字符的指令

我们可以利用命令行工具 stty 查询和配置 TTY,包括 line discipline 规则。
在 terminal 实行stty -a 命令:

$ stty -aspeed 38400 baud; rows 40; columns 80; line = 0;intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff-iuclc -ixany -imaxbel iutf8opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprtechoctl echoke -flusho -extproc

复制代码

-a 标志见告 stty 返回所有的设置,包括 TTY 的特色和 line discipline 规则。

让我们看一下第一行:

speed表示波特率。
当 terminal 和打算机通过物理线路连接时,speed 后的数字表示物理线路的波特率。
波特率对 PTY 来说是没故意义。
rows, columns表示 terminal 的行数和列数,以字符为单位。
line表示 line discipline 的类型。
0 是 N_TTY 。

stty 能够对 terminal 进行设置,让我们做个大略的测试验证一下。
在第一个 terminal 中利用 vi 编辑一个文件。
vi 在启动时会查询当前 terminal 的大小,以便 vi 能填满全体窗口。
这时候我们在另一个 terminal 中输入:

# stty -F /dev/pts/0 rows 20

复制代码

这个命令将终端 pts/0 的行数设置为原来的一半,这将更新内核中 TTY 的数据构造,并向 vi 发送一个 SIGWINCH 旗子暗记,vi 吸收到该旗子暗记后将根据 TTY 新的行列数重新绘制自己,这时 vi 就只利用了可用窗口区域的上半部分。

stty -a 输出的第二行给出了 line discipline 能处理的所有分外字符,包含了键的绑定。
例如intr = ^C 是指将 CTRL+c 映射到 kill -2 (SIGINT) 旗子暗记。
你也可以变动这个绑定,例如实行 stty intr o 命令,将发送 SIGINT 旗子暗记的键从 CTRL+c 换成了字符 o 。

末了, stty -a 列出了一系列 line discipline 规则的开关。
- 表示开关是关闭的,否则开关便是打开的。
所有的开关在 man stty 中都有阐明。
我举个中一个大略的例子, echo 是指示 line discipline 将字符回传的规则,我们可以实行命令关闭 echo 规则:

$ stty -echo

复制代码

这时候你再输入一些东西,屏幕上什么也不会涌现。
line discipline 不会将字符回传给 PTY master ,因此 terminal 不会再显示我们输入的内容。
然而其他统统都照常进行。
例如你输入 ls ,在输入时看不到字符 ls ,然后你输入回车后,仍旧会看到 ls 的输出。
实行命令规复 echo 规则:

$ stty echo

复制代码

可以通过 stty raw 命令来禁用所有的 line discipline 规则,这样的终端被称为 raw terminal。
像 vi 这样的编辑器会将终端设置为 raw ,由于它须要自己处理字符。
后面先容的远程终端也是须要一个 raw terminal ,同样会禁用所有的 line discipline 规则。

远程终端

我们常常通过 ssh 连接到一个远程主机,这时候远程主机上的 ssh server 便是一个伪终端 PTY,它同样持有 PTY master ,但 ssh server 不再监听键盘事宜,以及在屏幕上绘制输出结果,而是通过 TCP 连接,向 ssh client 发送或吸收字符。

我们大略梳理一下远程终端是如何实行命令的。

用户在客户真个 terminal 中输入 ssh 命令,经由 PTY master 、TTY 驱动,到达 PTY slave。
bash 的标准输入已经设置为了 PTY slave ,它从标准输入读取字符序列并阐明实行,创造须要启动 ssh 客户端,并要乞降远程做事器建 TCP 连接。
做事器端吸收客户真个 TCP 连接要求,向内核申请创建 PTY,得到一对设备文件描述符。
让ssh server 持有 PTY master , ssh server fork 出的子进程 bash 持有 PTY slave 。
bash 的标准输入、标准输出和标准缺点都设置为了 PTY slave 。
当用户在客户真个 terminal 中输入命令 ls -l 和回车键,这些字符经由 PTY master 到达 TTY 驱动。
我们须要禁用客户端 line discipline 的所有规则,也便是说客户真个 line discipline不会对分外字符回车键做处理,而是让命令 ls -l 和回车键一起到达 PTY slave 。
ssh client 从 PTY slave 读取字符序列,通过网络,发送给 ssh server 。
ssh server 将从 TCP 连接上吸收到的字节写入 PTY master 。
TTY 驱动对字节进行缓冲,直到收到分外字符回车键。
由于做事器真个 line discipline 没有禁用 echo 规则,以是 TTY 驱动还会将收到的字符写回PTY master , ssh server 从 PTY master 读取字符,将这些字符通过 TCP 连接发回客户端。
把稳,这是发回的字符不是 ls -l 命令的实行结果,而是 ls -l 本身的回显,让客户端能看到自己的输入。
在做事器端 TTY 驱动将字符序列传送给 PTY slave ,bash 从 PTY slave 读取字符,阐明并实行命令 ls -l 。
bash fork 出 ls 子进程,该子进程的标准输入、标准输出和标准缺点同样设置为了 PTY slave 。
ls -l 命令的实行结果写入标准输出 PTY slave ,然后实行结果通过 TTY 驱动到达 PTY master ,再由 ssh server 通过 TCP 连接发送给 ssh client 。

把稳在客户端,我们在屏幕上看到的所有字符都来自于远程做事器。
包括我们输入的内容,也是远程做事器上的 line discipline 运用 echo 规则的结果,将这些字符回显了回来。
表面看似大略的在远程终端上实行了一条命令,实际上底下确是波涛彭湃。

写在末了

大略回顾总结一下本文的紧张内容:

电传打字机(TTY)是物理设备,最初是为电报设计的,后来被连接到打算机上,发送输入和获取输出。
电传打字机(TTY)现在被运行在内核中的模块所仿照,被称为 终端仿照器(terminal emulator) 。
伪终端(pseudo terminal, PTY)是运行在用户区的终端仿照程序。
Shell 由 terminal fork 出来,是 terminal 的子进程。
Shell 不处理键盘事宜,也不卖力字符的显示,这些是由 terminal 处理。
Shell 卖力阐明实行用户输入的字符。
可以利用 stty 命令对 TTY 设备进行配置。
远程终端 ssh 也是一种 伪终端 PTY 。

相信通过这篇文章,你已经能够理解终端、终端仿照器和伪终真个差异和联系。
如果想进一步探究低层实现,可以阅读 TTY 驱动的源码 drivers/tty/tty_io.c 和 line discipline 的源码 drivers/tty/n_tty.c 。

原文 https://xie.infoq.cn/article/a6153354865c225bdce5bd55e

标签:

相关文章

QQ聊天恶搞代码技术背后的趣味与风险

人们的生活越来越离不开社交软件。在我国,QQ作为一款历史悠久、用户众多的社交平台,深受广大网民喜爱。在QQ聊天的过程中,恶搞代码的...

SEO优化 2025-03-02 阅读1 评论0

Python代码截屏技术与应用的完美融合

计算机屏幕截图已经成为人们日常生活中不可或缺的一部分。无论是分享工作成果、记录游戏瞬间,还是保存网页信息,屏幕截图都发挥着重要作用...

SEO优化 2025-03-02 阅读1 评论0

QQ无限刷礼物代码技术突破还是道德沦丧

社交平台逐渐成为人们生活中不可或缺的一部分。QQ作为我国最具影响力的社交软件之一,其丰富的功能吸引了大量用户。近期有关QQ无限刷礼...

SEO优化 2025-03-02 阅读1 评论0