每个伪终端(PTY)组件(软件,主控端,从属端)的职责是什么?


59

我试图找出一个tty是如何工作的1(每个元素的工作流程和职责)。我读了一些有趣的文章,但是仍然有一些模糊的地方。

到目前为止,这是我的理解:

  • 仿真终端会对/dev/ptmx伪终端的master部分进行不同的系统调用。
  • 伪终端的主机部分在中分配一个文件/dev/pts/[0-N],该文件对应于已过时的串行端口,并将从属伪终端“附加”到该文件。
  • 从属伪终端保留诸如会话ID,前台作业,屏幕大小之类的信息。

这是我的问题:

  1. ptmx除了分配从属部分还有其他用途吗?它提供某种“智能”,还是仿真的终端(例如xterm)具有像终端一样的所有智能?
  2. 为什么xterm只与从属部分的stdout和stdin转发,所以它必须与主控部分进行交互?为什么它不能 直接从pts文件写入和读取
  3. 会话ID是否总是附在一个pts文件上,反之亦然?我可以输入ps命令并为相同的/ dev / pts / X找到2个sessionId吗?
  4. pts商店还提供哪些其他信息?Xterm会自己更新所有字段,还是在其上ptm添加一些“智能”?

1.我的理解基于Linus Akesson揭秘TTYAndries BrouwerLinux Kernel帖子,以及这些站点上的其他几个问题

Answers:


58

终端模拟器

主站侧将替换连接到终端的线(一对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 ^Hspace^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)或当前输入或输出缓冲区中的另一个信息。TCGETSTCSETSTIOCGWINSZTIOCSWINSZtcsetpgrp()tcgetpgrp()TIOC{G,S}PGRP

注意,存储在终端设备中的屏幕尺寸信息可能无法反映现实。终端仿真器通常在调整窗口大小时(通过与主机大小相同的ioctl进行设置)进行设置,但是如果应用程序在从属端调用ioctl或未发送调整大小的情况下,终端仿真器可能会不同步ssh连接的含义,这意味着sshd如果ssh忽略SIGWINCH例如,则会产生另一个pty )。还可以通过转义序列查询某些终端的大小,因此应用程序可以通过这种方式查询它,并使用该信息更新线路规则。

有关更多详细信息,您可以查看例如Debian 上的termiostty_ioctl手册页。

与其他学科一起玩:

  1. 用伪终端模拟鼠标:

    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设备建立的符号链接) ,但应将其解释为鼠标输入事件。

  2. 创建一个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接口上传递。


1
这是最好的答案。我将其标记为正确并赞成。您可以添加有关pts存储的信息的最后一部分吗?根据此页面(配置TTY设备的章节),pts存储诸如行数和行数之类的值。他们还存储其他信息吗?
Pierre-Jean

@ Pierre-Jean,添加了更多信息。
斯特凡Chazelas

尽管您的答案远远超出令人满意的程度,但是有趣的是,看到了一个有关如何实际创建/ dev / pts / M的简单示例。我尝试使用cat /dev/ptmx &它将打开一个新的pty,但是没有找到与之相关的过程,那么您将如何使用它?其次,我尝试了echo "1" >/dev/ptmx,但是什么也没做...为什么我对此感兴趣?因为经常发生ssh(例如,当一个人通过)进行远程连接时,您会得到PTY allocation request failedNo controlling tty: open /dev/tty出错,从而阻止了作业控制。最好能更好地理解这些内容。
not2qubit 2014年

@ user1147688,如何创建pty将是一个不同的问题。这一次已经是太多问题了。但是请参阅您的pty手册页以获取详细信息。
斯特凡Chazelas

@StéphaneChazelas小澄清: 1,所以你说的是,流就像physical term---- tty---- bash终端上,并且pty(m)---- tty---- pty(s)---- bash在终端仿真器?是tty学科负责呼应物理终端的字符呢?2.是连接到键盘/屏幕来管理输入的终端仿真器程序吗?3.根据我的理解,您说过bash命令/所有终端输入的行缓冲是通过tty行规则而不是CI / O功能的I / O缓冲区完成的。这个对吗?
forumulator

28

编辑:自从这个答案以来,我在博客上写了一篇专门的文章,供那些对更多细节感兴趣的人使用。


经过大量阅读,这是我的理解。

  • ptmx除了分配从属部分还有其他用途吗?它提供某种“智能”,还是仿真终端(例如xterm)具有像终端一样的所有智能?

    /dev/ptmx不分配从属部分:它分配“伪终端主用部分”。/ dev / ptmx不是主伪终端:它是伪终端主多路复用器。它是使用Unix98 PTY标准创建的,以避免在分配主伪终端(source)时出现争用情况。

    伪终端的主要部分(ptm)未在文件系统上表示。它由文件描述符表示。

    所述从动部分(PTS)通过在文件表示/dev/pts/N,其中N是一个数字。

    该PTS被从PTM通过的连续调用中获得grandptunlockptptsname。(

    ptm替换了专用于与设备进行通信的AUR驱动程序以及线路版本。因此,它不以任何方式模拟终端,但提供了line edition的功能,并提供了一种可视化和与pt通信的方法。(来源

    这是连接到硬件设备的TTY的图表 与AUR的TTY通信

    这是连接到ptm的tty的图形 与PTM的TTY通信

    ptm文件处理与pts不同的Ioctl参数(ISPTM,UNLKPT,TIOCREMOTE,TIOCSIGNAL)。

  • 为什么xterm只与从属部分的stdout和stdin转发,所以它必须与主控部分进行交互?为什么不能直接从pts文件写入和读取?

    进程通过对虚拟文件执行的操作(读取,写入,ioctl ..)与设备进行交互。该文件本身不存在,并且驱动程序使用该文件在调用读取或写入方法时触发操作。(有关驱动程序的信息,请参阅附件)

    TTY定义了与之交互的精确方法。进程从设备进行读写操作,无论实现哪种TTY,都期望相同的行为。

    • 进程使用read函数从终端读取条目
    • 进程使用write函数输出发送到终端

    pt的行为类似于TTY驱动程序。其读取和写入方法用于实现TTY驱动程序行为。由于没有真正的设备来发送数据,因此将创建一个流对,并且ptm实现读取功能以读取pts发送给该流的数据,并执行写入功能将数据发送给该流。 pts何时阅读。

    请记住,代表设备的文件不是经典文件,并且如果xterm要查看已写入文件的内容,则不能仅将其简单地称为打开并读取它,因为此处的这些功能具有完全不同的行为。

  • 会话ID是否总是附在一个pts文件上,反之亦然?我可以键入ps命令并为相同的/ dev / pts / X找到2个sessionId吗?

    我不这么认为,会话ID是由附加pt的第一个进程定义的(通常是bash),我看不到创建另一个会话并将其附加到相同pt的方法。也许像socat这样的工具可以做到这一点?

  • pts还存储哪些其他信息?Xterm会自己更新所有字段吗,还是ptm会在上面添加一些“智能”?

    pts存储有关与之通信的终端的2类信息:Terminfo和和Termcap。通常,许多终端仿真器都是基于库来管理的,这些库可以为它们管理termcap信息(例如,它将提供所有功能值以仿真VTX100)。这种库的一个例子是libvte。编辑(请参阅Stephane Chazelas注释):终端不存储终端功能。

附件


termcap和terminfo是有关终端或终端仿真器功能的数据库,它们与tty或pty设备无关。
斯特凡Chazelas

好的,我将编辑答案。感谢您的评论。如果您知道答案,是否可以在答案中添加有关pts的信息(例如,pts确实存储屏幕尺寸)?
Pierre-Jean

6
这些都是不错的图像。您使用什么软件制作它们?
吉尔斯2014年

5
@吉尔斯谢谢你。我使用开源矢量图形编辑器Inkscape进行了这些操作。这可能不是执行这种图形的最有效方法,但是如果您有兴趣,我写了一篇有关如何创建这种等轴测图的文章。
皮埃尔·让(

我不认为您可以在一个控制终端上参加两个会话,也不能让一个会话拥有一个以上的控制终端
炸鱼薯条德里克

9

这是我前一段时间制定的有关sshd工作方式的方案。它与生产线纪律和东西的操作无关,但是它添加了一个现实的例子,说明谁与什么相互作用:

在此处输入图片说明


非常感谢你做的这些。我花了2天的时间来弄清楚。我只是想知道没有实例化时会发生什么。stdin不存在,可以,但是stdout和stderr写入哪里?
2015年

@emmasculateur很高兴它对您有所帮助。抱歉,“当没有实例化时”您无法理解。您能否举一个未实例化pty的示例?
鲍里斯·伯科夫

1
“没有实例化”是指当您使用ssh运行ssh时-T,该人说它将禁用伪终端分配。例如:ssh -T emasculateur@localhost "sleep 10" 那么 ps aux|grep sleep表明这一点: emasculateur 21826 0.0 0.0 23032 3728 ? Ss 02:49 0:00 zsh -c sleep 10 在做的bash写这种情况下,stdoutstderr?我希望我的问题有道理。
2015年

@emmasculateur hm,这是一个很好的问题,很有意义,我只是早些时候没有想到。我想就是这样,您可以在没有关联终端的情况下在远程计算机上以守护程序的身份启动进程。我的猜测是,它的标准输入/输出/错误就像/dev/null普通守护程序一样,但不确定。参见:serverfault.com/questions/593399/...
鲍里斯Burkov

@emmasculateur我也偶然发现了与您的情况不同的情况:如果您的进程曾经有终端,但是该终端已关闭,则在对stdout / stdin进行读/写尝试时,进程将从内核接收SIGHUP。这通常会终止不带nohupscreen/的ssh所启动的作业tmux
鲍里斯·伯科夫

0

man pts 说:

/ dev / ptmx文件是一个字符文件,其主号为5,次号为2,通常为0666模式,并且root.root为owner.group。它用于创建伪终端主对和从对。

当进程打开/ dev / ptmx时,它将获得伪终端主机(PTM)的文件描述符,并在/ dev / pts目录中创建伪终端从属(PTS)设备。通过打开/ dev / ptmx获得的每个文件描述符都是一个独立的PTM,具有自己的关联PTS,可以通过将描述符传递到ptsname(3)来找到其路径。

在打开伪终端从站之前,必须将主站的文件描述符传递给grantpt(3)和unlockpt(3)。

一旦伪终端主站和从站都打开,从站将为进程提供与真实终端相同的接口。

写入从属设备的数据作为输入显示在主设备描述符上。写入主机的数据作为输入提供给从机。

实际上,伪终端用于实现终端仿真器,例如xterm(1),其中从伪终端主设备读取的数据由应用程序以与真实终端解释数据相同的方式解释,并用于实现远程-login程序(例如sshd(8)),其中将从伪终端主机读取的数据通过网络发送到连接到终端或终端仿真器的客户端程序。

伪终端也可以用于将输入发送到通常拒绝从管道读取输入的程序(例如su(8)和passwd(8))。

关于/dev/pts/X indexing

每个X是您打开它的一个会话,因此从属需要索引。

关于TeteType (/dev/ttyN):

它是真正的控制台,它是由您的引导系统生成的sysV

关于为什么奴隶会被主人灌输: http ://commons.wikimedia.org/wiki/File:Termios-script-diagram.png


抱歉,您没有回答问题。我已经阅读了手册页并看到了此图,但是行为尚不清楚。如illuminÉ所示,您能否根据问题扩展您的回答?
Pierre-Jean

抱歉

要使用伪TTY子系统,必须安装一个用于主端驱动程序/ dev / ptmx的节点和N个从属驱动程序(在安装时确定N)。从设备的名称为/ dev / pts / M,其中M的值为0到N-1。用户通过主设备(称为ptm)访问伪TTY设备,该主设备又通过克隆驱动程序进行访问。主设备被设置为克隆设备,其中其主设备号是该克隆设备及其主设备的主设备号。次设备号是ptm驱动程序的主号。
PersianGulf 2014年

是的,我读了男人的潘页...。
PersianGulf 2014年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.