引言
在终端和运行的程序之间有一个终端行规程(见http://www.cnblogs.com/nufangrensheng/p/3575752.html中的图18-2),通过它我们能够在终端上设置特殊字符(退格、行删除、中断等)。但是,当一个登陆请求到达网络连接时,终端行规程并不是自动被加载到网络连接和登陆程序shell之间的。
概述
伪终端这个术语暗示对于一个应用程序而言,它看上去像一个终端,但事实上伪终端并不是一个真正的终端。下图显示了使用伪终端时相关进程的典型结构。其中关键点如下:
通常一个进程打开伪终端设备,然后调用fork。子进程建立了一个新会话,打开一个相应的伪终端从设备,将其描述符复制到标准输入、标准输出和标准出错,然后调用exec。伪终端从设备成为子进程的控制终端。
- 对于伪终端从设备上的用户进程来说,其标准输入、标准输出和标准出错都是终端设备。对于这些文件描述符,用户进程能够调用终端I/O章节中介绍的所有输入/输出函数。但是因为在伪终端从设备之下并没有真正的终端设备,无意义的函数调用(改变波特率、发送中断符、设置奇偶校验等)将被忽略。
- 任何写道伪终端设备的东西都会作为从设备的输入,反之亦然。事实上所有从设备端的输入都来自于伪终端主设备上的用户进程。这看起来像一个双向管道,但从设备上的终端行规程使我们拥有普通管道没有的其他处理能力。
我们通常用pty表示伪终端,而用tty表示终端。
伪终端的典型用途
网络登录服务器
伪终端可用于构造网络登录服务器。典型的例子是telnetd和rlogind服务器。一旦登陆shell运行在远端主机上,即可得到如下图所示的结构。Telnetd服务器使用类似的结构。
在rlogind服务器和登录shell之间有两个exec调用,这是因为login程序通常是在两个exec之间检验用户是否合法。
本图的另一个关键点是驱动PTY主设备的进程通常同时在读写另一个I/O流。图中另一个I/O流是TCP/IP框。这表示该进程必然使用了如select或poll那样的I/O多路转接,或被分成两个进程或线程。
script程序
script(1)程序是随大多数UNIX系统提供的,它将终端会话的所有输入和输出信息复制到一个文件中。它将自己置于终端和登录shell的一个新调用之间,从而完成此工作。下图详细描述了script程序中有关的交互。这里要特别指出,script程序通常是从登录shell启动的,该shell然后等待script程序的结束。
Script程序运行时,位于PTY从设备之上的终端行规程的所有输出都被复制到script文件中(通常叫做typescript)。因为击键通常由该行规程模块回显,所以该script文件也包括了输入的内容。但是,因为键入的口令(密码)不被回显,所以该文件不会包含口令。
expect程序
伪终端可以用来在非交互模式中驱动交互程序的运行。许多程序需要一个终端才能运行,passwd(1)命令就是一个例子,它要求用户在系统提示后输入命令。
为了支持处理操作模式而修改所有交互式程序,是非常麻烦的。相比之下,一个更好的解决方法是通过一个脚本来驱动交互式程序。Expect程序提供了这样的方法,它使用伪终端来运行其他程序。
运行协同进程
程序清单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库会将这两个流设置为行缓冲。
观看长时间运行程序的输出
使用任何一个标准shell,可以将一个需要长时间运行的程序放到后台去运行。但是如果将该程序的标准输出重定向到一个文件,并且它产生的输出又不多,那么我们就不能方便地监控程序的进展,这是因为标准I/O库会将标准输出全部放在缓冲区中。我们看到的将只是标准I/O库函数写到输出文件中的成块输出,有时甚至是大到8192字节的一块。
如果有源程序,则可以加入fflush调用。另一种方法是,可以在pty程序下运行该程序,让标准I/O库认为标准输出是终端。下图说明了这个结构,我们将这个缓慢输出的程序称为slowout。从登录shell到pty进程的fork/exec箭头用 虚线表示,以强调pty进程是作为后台任务运行的。