26.2 Rlogin协议
R l o g i n的第一次发布是在 4 . 2 B S D中,当时它仅能实现 U n i x主机之间的远程登录。这就使得R l o g i n比Te l n e t简单。由于客户进程和服务器进程的操作系统预先都知道对方的操作系统类型,所以就不需要选项协商机制。在过去的几年中, R l o g i n协议也派生出几种非 U n i x环境的版本。
RFC 1282 [Kantor 1991]详细说明了R l o g i n协议。类似于选路信息协议( R I P)的R F C,它是R l o g i n用了许多年后才发布的。 [Stevens 1990]的第1 5章介绍了远程登录的客户进程及服务器进程端的编程,并且给出了 R l o g i n的客户进程及服务器进程的完整源代码。 [ C o m e r和Stevens 1993]的第2 5章和第2 6章给出了Te l n e t的客户进程的实现细节和源代码。
26.2.1 应用进程的启动
R l o g i n的客户进程和服务器进程使用一个 T C P连接。当普通的T C P连接建立完毕之后,客户进程和服务器进程之间将发生下面所述的动作。
- 客户进程给服务器进程发送4个字符串:
(a)一个字节的0;
( b)用户登录进客户进程主机的登录名,以一个字节的0结束;
(c)登录服务器进程端主机的登录名,以一个字节的0结束;
(d)用户终端类型名,紧跟一个正斜杠“/”,然后是终端速率,以一个字节的0结束。在这里需要两个登录名字,这是因为用户登录客户和服务器的名称有可能不一样。由于大多满屏应用程序需要知道终端类型,所以终端类型也必须发送到服务器进程。发
送终端速率的原因是因为有些应用随着速率的改变,它的操作也有所变化。例如 v i编辑器,当速率比较小的时候,它的工作窗口也变小。所以它不能永远保持同样大小的窗口。 - 服务器进程返回一个字节的 0。
- 服务器进程可以选择是否要求用户输入口令。这个步骤的数据交互没有什么特别的协议,而被当作是普通的数据进行传输。服务器进程给客户进程发送一个字符串(显示在客户进程的屏幕上),通常是password: 。如果在一定的限定时间内(通常是 6 0秒)客户进程没有输入口令,服务器进程将关闭该连接。
通常可以在服务器进程的主目录 (home directory)下生成一个文件(通常叫 . r h o s t s),该文件的某些行记录了一个主机名和用户名。如果从该文件中已经记录的主机上用已经记录的用户名进行登录,服务器进程将不提示我们输入口令。但是很多关于安全性的文献,如[Curry 1992],强烈建议不要采用这种方法,因为这存在安全漏洞。
如果提示输入口令,那么我们输入的口令将以明文的形式发送到服务器进程。我们所键入的每个字符都是以明文的格式传输的。所以某人只要能够截取网络上的原始传输的分组,他就可以截获用户口令。针对这个问题,新版本的 R l o g i n客户程序,例如
4 . 4 B S D版本的客户程序,第一次采用了 K e r b e r o s安全模型。K e r b e r o s安全模型可以避免用户口令以明文的形式在网络上传输。当然,这要求服务器进程也支持 K e r b e r o s([Curry 1992]详细描述了K e r b e r o s安全模型)。 - 服务器进程通常要给客户进程发送请求,询问终端的窗口大小(将在后面解释)。客户进程每次给服务器进程发送一个字节的内容,并且接收服务器进程的所有返回信息。这在1 9 . 2节中已经介绍过了。同样我们也采用了 N a g l e算法(在1 9 . 4节中曾经介绍),该算法可以保证在速率较低的网络上,若干输入字节以单个 T C P报文段传输。操作其实很简单:用户键入的所有东西被发送到服务器,服务器发送给客户的任何信息返回到用户的屏幕上。
另外,服务器和客户之间还可以互相发送命令。在介绍这些命令之前,先介绍需要用到这些命令的场合。
26.2.2 流量控制
默认情况下,流量控制是由 R l o g i n的客户进程完成的。客户进程能够识别用户键入的S TO P和S TA RT的A S C I I字符(C o n t r o l_S和C o n t r o l_Q),并且终止或启动终端的输出。
如果不是这样,每次我们为终止终端输出而键入的 C o n t r o l _ S字符将沿网络传输到服务器进程,这时服务器进程将停止往网络上写数据。但是在写操作终止之前,服务器进程可能已经往网络上写了一窗口的输出数据。也就是说,在输出停止之前,成千上万的数据字节还将在屏幕上显示。图2 6 - 3显示了这个情况。
对于一个交互式用户来讲, C o n t r o l _ S字符的响应延时是较大的。
有时候,服务器的应用程序需要解释输入的每个字节,但又不想让客户对它的输入内容进行处理,例如对控制字符如 C o n t r o l _ S和C o n t r o l _ Q进行特殊处理(e m a c s编辑器就是这样的一个例子,它把 C o n t r o l _ S和C o n t r o l _ C作为自己的命令)。解决这个问题的办法就是由服务器告诉客户是否要进行流量控制。
26.2.3 客户的中断键
当我们为中断服务器正在运行的进程而键入一个中断字符时(通常是 D E L E T E或C o n t r o l _ C),会发生和流量控制相同的问题。
这个情况和图 2 6 - 3所示的类似,在一条 T C P连接的管道上,从服务器进程向客户进程正在发送大量的数据,而客户进程同时在向服务器进程传输中断字符。而我们的本意是要中断字符尽快终止某个进程,使屏幕上不再有任何响应输出。在流量控制和中断键这两种情况中,流量控制机制很少终止客户进程到服务器进程的数据流。这个方向仅仅包含我们键入的字符。所以对于从客户输出到服务器的特殊输入字符(C o n t r o l _ S和中断字符)不需要采用T C P的紧急方式(u rgent mode)。
26.2.4 窗口大小的改变
如果是窗口风格的显示方式,当应用程序在运行的时候,我们还可以动态地改变窗口的大小。一些应用程序(典型的如那些操作整个窗口的应用程序,如全屏编辑器)需要知道窗口大小的变化。目前大多数 U n i x系统提供这种功能,可以告诉应用程序关于窗口大小的变化。
对于远程登录这种情况,窗口大小的变化发生在客户端,而运行在服务器端的应用程序需要知道窗口大小变化。所以 R l o g i n的客户需要采用某些方法来通知服务器窗口大小变化的情况以及新窗口的大小。
26.2.5 服务器到客户的命令
现在我们介绍通过 T C P连接,R l o g i n服务器进程可以发送给客户进程的 4条命令。问题是只有一条T C P连接可供使用,所以服务器进程必须给这些命令字节做标记,使得客户进程可以从数据流中识别出这些是命令,而不是显示在终端上。所以我们将使用 T C P的紧急方式(在2 0 . 8节中曾经介绍)。
当服务器要给客户发送命令时,服务器就进入紧急方式,并且把命令放在紧急数据的最后一个字节中。当客户进程收到这个紧急方式通知时,它从连接上读取数据并且保存起来,直到读到命令字节(即紧急数据的最后一个字节)。这时候客户进程根据读到的命令,再决定对于所读到并保存起来的数据是显示在终端上还是丢弃它。图 2 6 - 4介绍了这4个命令。
采用T C P紧急方式发送这些命令的一个原因是第一个命令(“清仓输出(flush output)”)需要立即发送给客户,即使服务器到客户的数据流被窗口流量控制所终止。这种情况下,即服务器到客户的输出被流量控制所终止的情况是经常发生的,这是因为运行在服务器的进程的输出速率通常大于客户终端的显示速率。另一方面,客户到服务器的数据流很少被流量控制所终止,因为这个方向的数据流仅仅包含用户所键入的字符。
回忆一下图2 0 - 1 4中的例子,在那里我们介绍了即使窗口大小是 0时,紧急通知通过网络进行传输的情况(在下节中,我们还将介绍一个类似的例子)。其他的3个命令实时性并不特别强,但为了简单起见,也采用了和第一个命令相同的技术。
26.2.6 客户到服务器的命令
对于客户到服务器的命令,只定义了一条命令,那就是:将当前窗口大小发送给服务器。当客户的窗口大小发生变化时,客户并不立即向服务器报告,除非收到了服务器发来的 0 x 8 0命令(图2 6 - 4中有介绍)。
同样,由于只存在一条 T C P连接,客户必须对在连接上传输的该命令字节进行标注,使得服务器可以从数据流中识别出命令,而不是把它发送到上层的应用程序中去。处理的方法就是在两个字节的0 x ff后面紧跟着发送两个特殊的标志字节。
对于窗口大小命令,两个标志字节是 A S C I I码的字符‘s’。之后是4个16 bit长的数据(按网络字节顺序),分别是:行数(例如,2 5),每列的字符数(例如,8 0),X方向的像素数量,Y方向的像素数量。通常情况下,后两个 1 6 b i t是0,因为在R l o g i n服务器进程调用的应用程序中,通常是以字符为单位来度量屏幕的,而不是像素点。
上面我们介绍的从客户进程到服务器进程的命令采用带内信令( in-band signaling),这是因为命令字节和其他的普通数据一起传输。选择 0 x ff字节来表示这个带内信令的原因是:一般用户的操作不会产生0 x ff这个字节。所以说R l o g i n是不完备的,如果我们采用某种方法,使得通过键盘就可以产生两个连续的 0 x ff字节,而且正好在这之前是两个 A S C I I的‘s’字符,那么下面的8个字节就会被误认为是窗口大小了。
图2 6 - 4中介绍的是从服务器到客户的 R l o g i n命令,由于大多数的 A P I采用的技术叫做“带外数据(out-of-band data)”,所以我们就称它为带外信令 (out-of-band signaling)。但是回忆一下在2 0 . 8节中对T C P紧急方式的讨论,在那里我们说紧急方式数据不是带外数据,命令字节是按照普通数据流进行传输的,特殊之处是采用了紧急指针。
既然带内信令被用来传输从客户到服务器的命令,那么服务器进程必须检查从客户进程收到的每个字节,看看是否有两个连续的 0 x ff字节。但是对于采用带外信令的、从服务器传输到到客户的命令,客户进程不需要检查收到的每个字节,除非服务器进程进入了紧急方式。即使在紧急方式下,客户进程也仅仅需要留意紧急指针所指向的字节。而且由于从客户进程到服务器的数据流量和相反方向的数据流量之比是 1 : 2 0,这就暗示带内信令适合于数据量比较小的情况(从客户到服务器),而带外信令适合于数据量比较大的情况(从服务器到客户)。
26.2.7 客户的转义符
通常情况下,我们向R l o g i n客户进程键入的信息将传输到服务器进程。但是有些时候,我们并不需要把键入的信息传输到服务器,而是要和 R l o g i n客户进程直接通信。方法是在一行的开头键入代字符( t i l d e )“~”,紧跟着是下列4个字符之一:
- 以一个句号结束客户进程。
- 以文件结束符(通常是C o n t r o l _ D)结束客户进程。
- 以任务控制挂起符(通常是 C o n t r o l _ Z)挂起客户进程。
- 以任务控制延迟挂起符(通常是 C o n t r o l _ Y)来挂起仅仅是客户进程的输入。这时,不管客户运行什么程序,键入的任何信息将由该程序进行解释,但是从服务器发送到客户的信息还是输出到终端上。这非常适合当我们需要在服务器上运行一个长时间程序的场合,我们既想知道该程序的输出结果,同时还想在客户上运行其他程序。只有当客户进程的U n i x系统支持任务控制时,后两个命令才有效。