廊坊新闻网-主流媒体,廊坊城市门户

资讯推荐:计算机终端(计算机终端包括什么)

2022-09-26 20:32:31 来源:刀哥百科

计算机(计算机终端包括什么)

您可能听说过缩写TTY和PTY,并且在/dev目录中看到过/dev/TTY [n]设备。你大概知道它们和Linux终端的概念有关。但你知道TTY和PTY具体指的是什么,它们之间有什么区别,它们与壳牌有什么关系吗?要理解这一点,我们需要先回顾一下历史。


【资料图】

回顾历史

在计算机诞生之前,人们发明了电传打字机(Teleprinter),通过长导线点对点连接,收发打印的信息,用于电报信息的远距离传输。

电传打字机也可以写成电传打字机或电传打字机。

后来,人们把电传打字机连接到早期的大型计算机上,作为输入输出设备,把输入的数据送到计算机,打印出应答。

在今天,很难想象程序的运行结果需要打印出来才能看到。电传打字机设备已经进入计算机博物馆。目前,我们使用TTY来代表计算机终端,但我们只是遵循历史习惯。电传打字机曾经是计算机的终端,它的缩写是TTY (T ele TY pewriter)。

为了将不同类型的电传打字机连接到计算机,需要在操作系统的内核中安装驱动程序,为上层应用程序屏蔽所有底层细节。

电传打字机由两条电缆连接:一条用来向计算机发送指令,另一条用来接收计算机的输出。这两根电缆插入UART(通用异步收发器)的串行接口,与电脑相连。

操作系统包括一个UART驱动程序,它管理字节的物理传输,包括奇偶校验和流量控制。然后,输入的字符序列被传递给TTY驱动程序,它包含一个行规则。

行规负责转换特殊字符(如退格、擦字、清空行)并将接收到的内容传回电传打字机,以便用户看到输入的内容。行规也负责缓冲字符。当按下Enter键时,缓冲的数据被传递到与TTY相关的前台用户进程。用户可以并行执行几个进程,但一次只能与一个进程交互,而其他进程在后台工作。

终端仿真器(终端仿真器)

电传打字机今天已经进入博物馆,但Linux/Unix仍然保留了TTY驱动程序和线路规程的原始设计和功能。终端不再是需要通过UART连接到计算机物理设备。成为终端内核的一个模块,可以直接向TTY驱动发送字符,读取TTY驱动的响应并打印在屏幕上。也就是用内核模块来模拟物理终端设备,所以叫终端仿真器。

上图显示了一个典型的Linux桌面系统。模拟器就像过去的物理终端一样。它监视来自键盘的事件并将它们发送到TTY驱动程序,并读取来自TTY驱动程序的响应,通过显卡驱动程序将结果呈现到显示器上。TTY驱动程序和线路规则像以前一样运行,但是不再涉及UART和物理终端。

如何看一个终端模拟器?在Ubuntu 20桌面系统上,按Ctrl+Alt+F3得到一个内核模拟的TTY。Linux上的这种模拟文本终端也被称为虚拟控制台。每个虚拟终端用一个特殊的设备文件/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发来的信息。

伪终端,PTY)

终端仿真器是一个运行在内核中的模块。我们也可以让终端模拟器运行在用户区。运行在用户区的终端模拟程序称为伪终端,PTY)。

PTY运行在用户区,更加安全灵活,同时仍然保留了TTY驱动和线路纪律的功能。常用的伪终端包括xterm、gnome-terminal和远程终端ssh。我们以Ubuntu desktop提供的gnome-terminal为例,介绍伪终端如何与TTY驱动交互。

PTY是通过打开一个特殊的设备文件/dev/ptmx创建的,这个设备文件由一对双向字符设备组成,称为PTY master和pytsslave。

Gnome-terminal保存了PTY master的文件描述符/dev/ptmx。Gnome-terminal负责监控键盘事件,通过PTY master接收或发送字符到pytsslave,并在屏幕上绘制PTY master的字符输出。

Gnome-terminal将派生一个shell子进程,并让shell保存PYT slave的设备文件/dev/pts/[n]。shell通过PYT从机接收字符并输出处理结果。

ptmaster和PYT slave之间使用TTY驱动程序,它将在主从之间复制数据,管理会话并提供线路纪律功能。

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

$ 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。

让我们举一个实际的例子来看看在终端中执行一个命令的全过程。

我们在桌面上启动终端程序gnome-terminal,它向操作系统请求一个PTY master并在显示器上绘制GUI。

gnome-终端启动子进程bash

Bash的标准输入、标准输出和标准错误都被设置为PYT slave。

Gnome终端监听键盘事件,并将输入字符发送给PTY主机。

Line规程接收字符并缓冲它们。只有当你按下回车键,它会复制缓冲字符到PYT奴隶。

当接收到字符时,线路规程会将字符写回PTY主机。Gnome终端只会在屏幕上显示来自PTY master的东西。所以行规需要返回字符,这样你就可以看到你刚才打的是什么。

当您按下回车键时,TTY驱动程序负责将缓冲的数据复制到PYT从机

Bash从标准输入中读取输入字符(例如,ls -l)。注意,bash已经在启动时将标准输入设置为PYT从属服务器。

Bash解释从输入中读取的字符,并发现需要运行ls。

Bash fork退出ls进程。bash fork的进程与bash具有相同的标准输入、标准输出和标准错误,即PYT从机。

Ls运行,结果打印到标准输出,即PYT从。

TTY驱动程序将字符复制到PTY主机。

Gnome-terminal循环从PTY master读取字节,并将它们绘制在用户界面上。

通常,我们不会区分终端和外壳。我们说打开一个终端或者一个外壳。从上面描述的命令执行过程可以看出,Shell不处理键盘事件,也不负责字符的显示,这是终端必须为其处理的事情。

Shell是用户空之间的应用,通常来自终端fork,是终端的子进程。Shell用于提示用户输入,解释用户输入的字符,然后处理底层操作系统的输出。

通常我们用的比较多的shell比如Bash,Zsh,sh。

配置TTY设备

内核将使用TTY驱动程序来处理终端和Shell之间的通信。生产线纪律是TTY驱动程序的逻辑组成部分。线路规程主要有以下功能:

当用户输入时,字符将返回给PTY主机。

线规则在内存中缓冲这些字符。当用户按下回车键时,它将这些字符发送给PYT从机。

线规可以截取一些特殊的功能键,比如:

当用户按下CTRL+c时,它向连接到PYT从机的进程发送一个kill -2(SIGINT)信号。

当用户按CTRL+w时,它删除用户输入的最后一个单词。

当用户按下CTRL+z时,它向连接到PYT从机的进程发送一个kill -STOP信号。

当用户按退格键时,它从缓冲区中删除字符,并向PTY主机发送删除最后一个字符的指令。

我们可以使用命令行工具stty来查询和配置tty,包括线路规程规则。在终端中执行stty -a命令:

$ stty -aspeed 38400 baud; rows 40; columns 80; line = 0;intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ;eol2 = ; swtch = ; 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的特征和线路规程规则。

让我们看第一行:

表示速度波特率。当终端和计算机通过物理线路连接时,速度后面的数字表示物理线路的波特率。波特率对PTY没有意义。

Rows,columns表示端子的行数和列数,以字符为单位。

指示线规程的类型。TTY北部。

Stty可以设置终端。让我们做一个简单的测试来验证一下。使用vi在第一个终端中编辑文件。当vi启动时,它将查询当前终端的大小,以便vi可以填充整个窗口。这时我们进入另一个终端:

# 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列出了一系列线路规程规则的转换。-表示开关闭合,否则开关断开。所有开关都用Mansty解释。我举个简单的例子。echo是指示线路规程传回字符的规则。我们可以执行命令来关闭echo规则:

$ stty -echo

复制代码

这时,如果你再键入一些东西,屏幕上什么也不会出现。Line discipline不会将字符传回PTY master,因此终端将不再显示我们输入的内容。然而,其他一切照常进行。比如输入ls,输入的时候看不到ls这个字符,然后输入enter之后还是会看到ls的输出。执行命令以恢复回显规则:

$ stty echo

复制代码

您可以通过stty raw命令禁用所有线路规程规则,这样的终端称为原始终端。像vi这样的编辑器会把终端设置成raw,因为它需要自己处理字符。后面介绍的远程终端也需要一个raw终端,它也会禁用所有的线路规程规则。

远程终端

我们经常通过ssh连接到远程主机。此时,远程主机上的ssh服务器是一个伪终端PTY,它也持有PTY master。但是,ssh服务器不再监控键盘事件并在屏幕上绘制输出结果,而是通过TCP连接向ssh客户端发送或接收字符。

我们简单梳理一下远程终端是如何执行命令的。

在客户端终端输入ssh命令,通过PTY主机和TTY驱动程序到达PTY从机。Bash的标准输入被设置为PTY slave,它从标准输入中读取字符序列并解释执行。当它发现需要启动ssh客户机时,它请求与远程服务器建立TCP连接。

服务器接收来自客户端的TCP连接请求,向内核申请创建PTY,并获得一对设备文件描述符。让ssh服务器持有PTY master,ssh服务器fork的子进程bash持有PTY slave。Bash的标准输入、标准输出和标准错误都设置为PTY slave。

当用户在客户端终端输入命令ls -l和回车键时,这些字符通过PTY master到达TTY驱动程序。我们需要禁用客户端line规程的所有规则,也就是说客户端line规程不会处理特殊字符enter键,而是让命令ls -l和enter键一起到达PTY slave。客户端从PTY slave读取字符序列,并通过网络发送给ssh服务器。

Ssh服务器将从TCP连接接收的字节写入PTY主机。TTY驱动程序缓冲字节,直到它收到特殊字符回车键。

因为服务器端的line规程没有禁用echo规则,所以TTY驱动也会将接收到的字符写回PTY master,ssh服务器从PTY master读取字符,通过TCP连接发送回客户端。注意,这是发回的字符,不是ls -l命令的执行结果,而是ls -l本身的回显,让客户端看到自己的输入。

在服务器端,TTY驱动程序将字符序列传输给PTY从机,bash从PTY从机读取字符,解释并执行命令ls -l..Bash fork退出ls子进程,其标准输入、标准输出和标准错误也设置为PTY slave。ls -l命令的执行结果被写入标准输出PTY slave,然后执行结果通过TTY驱动到达PTY master,再由ssh服务器通过TCP连接发送到ssh客户端。

注意,在客户端,我们在屏幕上看到的所有字符都来自远程服务器。包括我们输入的内容,这也是远程服务器上的行规则应用回显规则的结果,回显规则回显这些字符。表面上看,在远程终端上执行了一个命令,但实际上它非常粗糙。

写在最后

简要回顾和总结本文的主要内容:

电传打字机(TTY)是一种物理设备,最初是为电报设计的,后来连接到计算机上发送输入并获得输出。

电传打字机(TTY)现在由运行在内核中的模块模拟,被称为终端仿真器。

伪终端,PTY)是运行在用户区的终端模拟程序。

Shell出自terminal fork,是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

关键词: 驱动程序 电传打字机 线路规程