终端模拟器
主站侧将替换连接到终端的线(一对TX / RX线)。
终端在一根导线上显示它接收到的字符(其中一些是控制字符,并使其执行诸如移动光标,更改颜色等操作),并在另一根导线上发送与您键入的键相对应的字符。
像xterm这样的终端仿真器没有什么不同,除了它们不是通过电线发送和接收字符,而是在文件描述符中将字符读写到主端。一旦他们产生了从属终端,并在该终端上启动了外壳程序,他们就不再碰它了。除了模拟这对线材外,xterm还可以通过该文件描述符将某些线规属性更改为主端。例如,它们可以更新大小属性,以便将SIGWINCH发送到与从属pty交互的应用程序,以通知它们更改的大小。
除此之外,终端/终端仿真器中几乎没有智能。
您写到终端设备(如pty从站)的意思是要在那里显示,从那里读取的内容是您在其中键入的内容,因此终端仿真器无法对该终端设备进行读取或写入操作。他们是另一端的人。
tty线学科
很多的情报是在tty线路纪律。线路规程是一个软件模块(位于驱动程序中,位于内核中),推入位于该设备与线路/电线(pty的主端)之间的串行/ pty设备之上。
串行线的另一端可以有一个终端,但也可以有鼠标或另一台用于联网的计算机。例如,您可以附加一个SLIP线路规程,以在串行设备(或pty设备)的顶部获得网络接口,或者您可以拥有tty线路规程。tty线规是至少在Linux上针对串行和pty设备的默认线规。在Linux上,您可以使用更改线规ldattach
。
您可以通过发出命令来禁用tty行纪律的效果stty raw -echo
(请注意,bash提示或其他交互式应用程序,例如vi
将终端设置为所需的确切模式,因此您想使用像这样的笨拙的应用程序cat
)。然后,写入从属终端设备的所有内容都会立即传送到主机,供xterm读取,并且xterm写入主机的每个字符都可立即用于从属设备读取。
线路规则是在终端设备内部线路编辑器中实现的地方。例如,使用stty icanon echo
(作为默认设置),当您键入时a
,xterm将写入a
主服务器,然后行规程将其回显(a
可用于读取以xterm
供显示),但不会使任何内容可用于从属侧读取。然后,如果您键入backspace,则xterm将发送一个^?
或^H
字符,该线规(与线规设置相对应^?
或^H
与之相对应erase
)在主机上发送回a ^H
,space
并^H
用于xterm
擦除a
您刚刚在屏幕上键入内容,但仍然不会向从属设备读取的应用程序发送任何内容,它只是更新其内部行编辑器缓冲区以删除a
您之前键入的内容。
然后,当您按Enter键时,xterm发送^M
(CR),行规则将输入的内容转换为^ J(LF),然后将您到目前为止输入的内容发送到从属端进行读取(正在读取的应用程序/dev/pts/x
将接收到您输入的内容包括LF,但a
由于您已删除,所以不包含LF ),而在主设备端,它会发送CR和LF,将光标移至下一行和屏幕的开头。
线规还负责在主机接收到字符等时将SIGINT
信号发送到终端的前台处理组^C
。
许多交互式终端应用程序禁用该行规程的大多数功能以自行实现。但是无论如何,请注意终端(xterm
)几乎没有参与(除了显示被告知要显示的内容)。
每个进程和每个终端设备只能有一个会话。会话可以具有连接的控制终端,但不是必须的(所有会话都在没有终端的情况下开始,直到它们打开一个终端为止)。xterm
,在它派生执行Shell的过程中,通常会创建一个新会话(并因此从您启动的终端分离(xterm
如果有的话))/dev/pts/x
,通过将该终端设备连接到新会话上来打开它所产生的新会话。然后它将在该过程中执行您的Shell,因此您的Shell将成为会话领导者。您在该会话中的shell或任何交互式shell通常会与进程组和tcsetpgrp()
进行交互,以设置该终端的前台和后台作业。
关于由tty学科(串行或pty)的终端设备存储哪些信息,通常就是stty
命令显示和修改的内容。所有学科配置:终端屏幕大小,本地,输入输出标志,特殊字符(如^ C,^ Z ...)的设置,输入和输出速度(与pty不相关)。这对应于在Linux 上映射到/ ioctls 的tcgetattr()
/ tcsetattr()
函数,以及/ 用于屏幕大小。您可能会争辩说,当前前台进程组是存储在终端设备(/ ,ioctls)或当前输入或输出缓冲区中的另一个信息。TCGETS
TCSETS
TIOCGWINSZ
TIOCSWINSZ
tcsetpgrp()
tcgetpgrp()
TIOC{G,S}PGRP
注意,存储在终端设备中的屏幕尺寸信息可能无法反映现实。终端仿真器通常在调整窗口大小时(通过与主机大小相同的ioctl进行设置)进行设置,但是如果应用程序在从属端调用ioctl或未发送调整大小的情况下,终端仿真器可能会不同步ssh连接的含义,这意味着sshd
如果ssh
忽略SIGWINCH
例如,则会产生另一个pty )。还可以通过转义序列查询某些终端的大小,因此应用程序可以通过这种方式查询它,并使用该信息更新线路规则。
有关更多详细信息,您可以查看例如Debian 上的termios
和tty_ioctl
手册页。
与其他学科一起玩:
用伪终端模拟鼠标:
socat pty,link=mouse fifo:fifo
sudo inputattach -msc mouse # sets the MOUSE line discipline and specifies protocol
xinput list # see the new mouse there
exec 3<> fifo
printf '\207\12\0' >&3 # moves the cursor 10 pixels to the right
在上面,pty的主端通过socat终止到命名管道(fifo
)上。我们将该fifo连接到一个写0x87 0x0a 0x00的进程(外壳),这在鼠标系统协议中表示no button pressed, delta(x,y) = (10,0)
。在这里,我们(外壳程序)不是在模拟终端,而是鼠标,我们发送的3个字节不会被终端设备的应用程序读取(可能转换)(mouse
在上面是由socat
某个/dev/pts/x
设备建立的符号链接) ,但应将其解释为鼠标输入事件。
创建一个SLIP界面:
# on hostA
socat tcp-listen:12345,reuseaddr pty,link=interface
# after connection from hostB:
sudo ldattach SLIP interface
ifconfig -a # see the new interface there
sudo ifconfig sl0 192.168.123.1/24
# on hostB
socat -v -x pty,link=interface tcp:hostA:12345
sudo ldattach SLIP interface
sudo ifconfig sl0 192.168.123.2/24
ping 192.168.123.1 # see the packets on socat output
上面,串行线被模拟socat
为hostA和hostB之间的TCP套接字。SLIP线路规程将在该虚拟线路上交换的那些字节解释为SLIP封装的IP数据包,以在sl0
接口上传递。