Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2088027
  • 博文数量: 414
  • 博客积分: 10312
  • 博客等级: 上将
  • 技术积分: 4921
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-31 01:49
文章分类

全部博文(414)

文章存档

2011年(1)

2010年(29)

2009年(82)

2008年(301)

2007年(1)

分类: C/C++

2008-03-10 07:18:43

伪终端

19.1 引言

9章介绍进行终端登录时,需要通过一个终端设备自动提供终端的语义。在终端和运行

程序之间有一个终端行规程(见图11 - 2),通过这个规程我们能够在终端上设置特殊字符(退

格、行删除、中断等)。但是,当一个登录请求到达网络连接时,终端行规程并不是自动被加

载到网络连接和登录程序s h e l l之间的。9 - 5显示了一个伪终端设备驱动程序被用来提供终端

语义。

除了用于网络登录,伪终端还被用在其他方面,本章将对此进行介绍。我们将首先提供

S V R 44 . 3 + B S D系统下用于创建伪终端的函数,然后使用这些函数编写一个程序用来调用p t y

我们将看到这个程序的各种使用:在输入字符和终端显示之间进行转换 B S D的码转换程序)和运行协同进程来避免程序1 4 - 1 0中遇到的缓存问题

19.2 概述

终端(pseudo terminal)这个名词暗示了与一个应用程序相比,它更加像一个终端。但

事实上,伪终端并不是一个真正的终端。图1 9 -1显示了使用伪终端的进程的典型结构。其中

关键点如下:

(1) 通常一个进程打开伪终端主设备然后调用f o r k。子进程建立了一个新的对话,打开

一个相应的伪终端从设备,将它复制成标准输入、标准输出和标准出错,然后调用e x e c

终端从设备成为子进程的控制终端

(2) 对于伪终端从设备之上的用户进程来说其标准输入、标准输出和标准出错都能当作终端设备使用。用户进程能够调用11章中讲到的所有输入/输出函数。但是因为在伪终端从设备之下并没有真正的设备无意义的函数调用(改变波特率、发送中断符、设置奇偶校验等)将被忽略。

(3) 任何写到伪终端主设备的输入都会作为从设备端的输入,反之亦然。事实上所有从设备端的输入都来自于主设备上的用户进程。这看起来就像一个流管道(见图1 5 - 3),但从设备上的终端行规程使我们拥有普通管道之外的其他处理能力。

1 9 - 1显示了B S D系统中的伪终端结构。1 9 . 3 . 2节将介绍如何打开这些设备。S V R 4系统中伪终端是使用流系统来创建的(见1 2 . 4节)。图1 9 - 2详细描述了S V R 4系统中各个伪终端模块之间的关系。虚线框中的两个流模块是可选的。请注意从设备上的三个流模块同程序1 2 - 1 0(网络登录)的输出是一样的。1 9 . 3 . 1节将介绍如何组织这些流模块。

从现在开始将简化以上图示,首先不再画出图1 9 - 1读、写功能或图1 9 - 2的流首。使

用缩写p t y表示伪终端,并将图1 9 - 2中所有伪终端从设备之上的流模块集合表示为终端行规程模块。

19.2.1 网络登录服务器

伪终端用于构造网络登录服务器。典型的例子是t e l n e t dr l o g i n d服务器。S t e v e n s1 9 9 0〕第1 5章详细讨论了提供r l o g i n服务的步骤。一旦登录s h e l l运行在远端主机上,即可得到如图1 9 -3的结构。同样的结构也用于t e l n e t d服务器。

r l o g i n d服务器和登录s h e l l之间有两个e x e c调用,这是因为l o g i n程序通常是在两个e x e c之间检验用户是否合法的。

本图的一个关键点驱动伪终端主设备的进程通常同时在读写另一个I / O。本例中另一个I / O流是T C P / I P。这表示该进程必然使用了某种形式的如s e l e c tp o l l那样的I / O多路转接(见1 2 . 5节),或被分成两个进程。回忆1 8 . 7节讨论过的一个进程和两个进程的比较。

19.2.2 script程序

s c r i p t程序是随S V R 44 . 3 + B S D提供的,该程序将终端对话期间所有的输入和输出信息在一个文件中做一个拷贝。它通过将自己置于终端和登录s h e l l的一个新的调用之间来完成这个工作。图1 9 - 4详细描述了s c r i p t程序相关的交互。这里特别指出s c r i p t程序通常是从登录s h e l l起动的,该s h e l l然后等待程序的结束s c r i p t程序运行时,在伪终端从设备之上终端行规程的所有输出都被复制到一个s c r i p t文件中(通常叫做t y p e s c r i p t)。因为击键通常被行规程的模块回显,该s c r i p t文件也包括了输入的内容。但是,因为口令不被回显,该s c r i p t文件不会包含口令。

本书中所有运行程序并显示其输出的实例都是由s c r i p t程序实现的,这样避免了手动拷贝程序输出可能带来的错误。

1 9 . 5开发一个通用的p t y程序后,我们将看到一个巧妙的s h e l l脚本能够将它转化成一个s c r i p t程序

19.2.3 expect程序

伪终端可以用来使交互式的程序运行在非交互的状态中。许多程序需要一个终端来运行,1 8 . 7节中的c a l l进程就是一个例子。它假定标准输入是一个终端并在起动时将其设置为初始模式(见程序1 8 - 2 0)。该程序不能被s h e l l脚本用来运行以自动拨号到远程系统,登录,取出信息和注销。同修改所有交互式程序来支持批处理模式的操作比较,一个更好的解决方法是通过一个s c r i p t来驱动交互式程序。e x p e c t程序[Libes 1990;1991]提供了这样的方法。类似于1 9 . 5节的p t y程序,它使用伪终端来运行其他程序。并且, e x p e c t还提供了一种编程语言用于检查程序的输出,以确定用什么作为输入发送给该程序。当一个交互式的程序开始从一个脚本运行时,不能仅仅是将脚本中的所有内容输入到程序中去。相应的,要通过检查程序的输出来决定下一步输入的内容。

19.2.4 运行协同进程

在程序1 4 - 1 0所示的例子中,不能调用使用标准I / O库进行输入、输出的协同进程,这是因为当通过管道与协同进程进行通讯时,标准I / O库会将标准输入和输出的内容放到缓存中,从

而引起死锁。如果协同进程是一个已经编译的程序而我们又没有源程序,则无法在源程序中加

ff l u s h语句来解决这个问题。图8显示了一个进程驱动协同进程的情况。我们只需将一个伪终

端放到两个进程之间,见图1 9 - 5

现在协同进程的标准输入和标准输出就像终端设备一样,所以标准I / O库会将这两个流设置为行缓存。父进程有两种不同的方法在自身和协同进程之间获得伪终端(这种情况下的父进程可以类似程序1 4 - 9使用两个管道和协同进程进行通讯;或者像程序1 5 - 1那样,使用一个流管道)一个方法是父进程直接调用p t y _ f o r k函数(见1 9 . 4节)而不是f o r k一种方法是e x e cp t y程序,将协同进程作为参数(见1 9 . 5节)。我们将在说明p t y程序后介绍这两种方法。

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

使用任一个标准s h e l l,都可以将一个需要长时间运行的程序放到后台运行。但是如果将该

程序的标准输出重定向到一个文件,并且如果它产生的输出不多,我们就不能方便地监控程序的进展,这是因为标准I / O库会将标准输出放在缓存中保存。我们看到的将只是成块的输出结果,有时甚至可能是8 1 9 2字节一块如果有源程序,则可以加入ff l u s h调用另一种方法是,可以在p t y程序下运行该程序,让标准I / O库认为输出是终端。图1 9 - 6说明了这个结构,我们将这个缓慢输出的程序称为s l o w o u t。从登录s h e l lp t y进程的f o r t / e x e c箭头用虚线表示,以强调p t y进程是作为后台任务运行的。

 

阅读(823) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~