伪终端

引言

在终端和运行的程序之间有一个终端行规程(见http://www.cnblogs.com/nufangrensheng/p/3575752.html中的图18-2),通过它我们能够在终端上设置特殊字符(退格、行删除、中断等)。但是,当一个登陆请求到达网络连接时,终端行规程并不是自动被加载到网络连接和登陆程序shell之间的。

概述

伪终端这个术语暗示对于一个应用程序而言,它看上去像一个终端,但事实上伪终端并不是一个真正的终端下图显示了使用伪终端时相关进程的典型结构。其中关键点如下:

    通常一个进程打开伪终端设备,然后调用fork。子进程建立了一个新会话,打开一个相应的伪终端从设备,将其描述符复制到标准输入、标准输出和标准出错,然后调用exec。伪终端从设备成为子进程的控制终端。

  1. 对于伪终端从设备上的用户进程来说,其标准输入、标准输出和标准出错都是终端设备。对于这些文件描述符,用户进程能够调用终端I/O章节中介绍的所有输入/输出函数。但是因为在伪终端从设备之下并没有真正的终端设备,无意义的函数调用(改变波特率、发送中断符、设置奇偶校验等)将被忽略。
  2. 任何写道伪终端设备的东西都会作为从设备的输入,反之亦然。事实上所有从设备端的输入都来自于伪终端主设备上的用户进程。这看起来像一个双向管道,但从设备上的终端行规程使我们拥有普通管道没有的其他处理能力。

我们通常用pty表示伪终端,而用tty表示终端。

伪终端的典型用途

  1. 网络登录服务器

    伪终端可用于构造网络登录服务器。典型的例子是telnetd和rlogind服务器。一旦登陆shell运行在远端主机上,即可得到如下图所示的结构。Telnetd服务器使用类似的结构。

    在rlogind服务器和登录shell之间有两个exec调用,这是因为login程序通常是在两个exec之间检验用户是否合法。

    本图的另一个关键点是驱动PTY主设备的进程通常同时在读写另一个I/O流。图中另一个I/O流是TCP/IP框。这表示该进程必然使用了如select或poll那样的I/O多路转接,或被分成两个进程或线程。

  2. script程序

    script(1)程序是随大多数UNIX系统提供的,它将终端会话的所有输入和输出信息复制到一个文件中。它将自己置于终端和登录shell的一个新调用之间,从而完成此工作。下图详细描述了script程序中有关的交互。这里要特别指出,script程序通常是从登录shell启动的,该shell然后等待script程序的结束。

    Script程序运行时,位于PTY从设备之上的终端行规程的所有输出都被复制到script文件中(通常叫做typescript)。因为击键通常由该行规程模块回显,所以该script文件也包括了输入的内容。但是,因为键入的口令(密码)不被回显,所以该文件不会包含口令。

  3. expect程序

    伪终端可以用来在非交互模式中驱动交互程序的运行。许多程序需要一个终端才能运行,passwd(1)命令就是一个例子,它要求用户在系统提示后输入命令。

    为了支持处理操作模式而修改所有交互式程序,是非常麻烦的。相比之下,一个更好的解决方法是通过一个脚本来驱动交互式程序。Expect程序提供了这样的方法,它使用伪终端来运行其他程序。

  4. 运行协同进程

    程序清单15-10(http://www.cnblogs.com/nufangrensheng/p/3561379.html)所示的协同进程例子中,我们不能调用使用标准I/O库进行输入、输出的协同进程,这是因为当通过管道与协同进程进行通信时,标准I/O库会将标准输入和输出的内容放到缓冲区中,从而引起死锁。如果协同进程是一个已经编译的程序而我们又没有源程序,则无法在源程序中加入fflush语句来解决这个问题。图15-8(http://www.cnblogs.com/nufangrensheng/p/3561379.html)显示了一个进程驱动协同进程的情况。我们须要做的是将一个伪终端放到两个进程之间(如下图所示),这诱使协同进程认为它是由终端而非另一个进程驱动的。

    现在协同进程的标准输入和标准输出就像终端设备一样,所以标准I/O库会将这两个流设置为行缓冲。

  5. 观看长时间运行程序的输出

    使用任何一个标准shell,可以将一个需要长时间运行的程序放到后台去运行。但是如果将该程序的标准输出重定向到一个文件,并且它产生的输出又不多,那么我们就不能方便地监控程序的进展,这是因为标准I/O库会将标准输出全部放在缓冲区中。我们看到的将只是标准I/O库函数写到输出文件中的成块输出,有时甚至是大到8192字节的一块。

    如果有源程序,则可以加入fflush调用。另一种方法是,可以在pty程序下运行该程序,让标准I/O库认为标准输出是终端。下图说明了这个结构,我们将这个缓慢输出的程序称为slowout。从登录shell到pty进程的fork/exec箭头用 虚线表示,以强调pty进程是作为后台任务运行的。

原文地址:https://www.cnblogs.com/nufangrensheng/p/3577853.html