TCP/IP详解 卷一 Telnet和Rlogin:远程登录
发表于:2025-10-26 | 分类: 学习
Telnet和Rlogin:远程登录

概述

远程登录( Remote Login)是Internet上最广泛的应用之一。我们可以先登录(即注册)到一台主机然后再通过网络远程登录到任何其他一台网络主机上去,而不需要为每一台主机连接一个硬件终端(当然必须有登录帐号)

在TCP/IP网络上,有两种应用提供远程登录功能。

  1. Telnet是标准的提供远程登录功能的应用,几乎每个TCP/IP的实现都提供这个功能。它能够运行在不同操作系统的主机之间。Telnet通过客户进程和服务器进程之间的选项协商机制,从而确定通信双方可以提供的功能特性。
  2. Rlogin起源于伯克利Unix,开始它只能工作在Unix系统之间,现在已经可以在其他操作系统上运行。

远程登录采用客户- 服务器模式,下图显示的是一个Telnet客户和服务器的典型连接图:

在这张图中,有以下要点需要注意:

  1. Telnet客户进程同时和终端用户和TCP/IP协议模块进行交互。通常我们所键入的任何信息的传输是通过TCP连接,连接的任何返回信息都输出到终端上。
  2. Telnet服务器进程经常要和一种叫做“伪终端设备”(pseudo-terminal device)打交道,至少在Unix系统下是这样的。这就使得对于登录外壳 (shell )进程来讲,它是被Telnet服务器进程直接调用的,而且任何运行在登录外壳进程处的程序都感觉是直接和一个终端进行交互。对于像满屏编辑器这样的应用来讲,就像直接在和终端打交道一样。实际上,如何对服务器进程的登录外壳进程进行处理,使得它好像在直接和终端交互,往往是编写远程登录服务器
  3. 仅仅使用了一条TCP连接。由于客户进程必须多次和服务器进程进行通信(反之亦然),这就必然需要某些方法,来描绘在连接上传输的命令和用户数据。
  4. 我们用虚线框把终端驱动进程和伪终端驱动进程框了起来。在TCP/IP实现中,虚线框的内容一般是操作系统内核的一部分。Telnet客户进程和服务器进程一般只是属于用户应用程序。
  5. 把服务器进程的登录外壳进程画出来的目的是为了说明:当我们想登录到系统的时候,必须要有一个帐号,Telnet和Rlogin都是如此。

Rlogin协议

Rlogin的第一次发布是在4.2BSD中,当时它仅能实现Unix主机之间的远程登录。这就使得Rlogin比Telnet简单。由于客户进程和服务器进程的操作系统预先都知道对方的操作系统类型,所以就不需要选项协商机制。在过去的几年中, Rlogin协议也派生出几种非Unix环境的版本。

  1. 应用进程的启动

    Rlogin的客户进程和服务器进程使用一个TCP连接。当普通的TCP连接建立完毕之后,客户进程和服务器进程之间将发生下面所述的动作。

    1. 客户进程给服务器进程发送4个字符串:(a)一个字节的0;(b)用户登录进客户进程主机的登录名,以一个字节的0结束;(c)登录服务器进程端主机的登录名,以一个字节的0结束;(d)用户终端类型名,紧跟一个正斜杠“/”,然后是终端速率,以一个字节的0结束。在这里需要两个登录名字,这是因为用户登录客户和服务器的名称有可能不一样。由于大多满屏应用程序需要知道终端类型,所以终端类型也必须发送到服务器进程。发送终端速率的原因是因为有些应用随着速率的改变,它的操作也有所变化。例如vi编辑器,当速率比较小的时候,它的工作窗口也变小。所以它不能永远保持同样大小的窗口。
    2. 服务器进程返回一个字节的 0。
    3. 服务器进程可以选择是否要求用户输入口令。这个步骤的数据交互没有什么特别的协议,而被当作是普通的数据进行传输。服务器进程给客户进程发送一个字符串(显示在客户进程的屏幕上),通常是password: 。如果在一定的限定时间内(通常是 6 0秒)客户进程没有输入口令,服务器进程将关闭该连接。
    4. 服务器进程通常要给客户进程发送请求,询问终端的窗口大小。

    客户进程每次给服务器进程发送一个字节的内容,并且接收服务器进程的所有返回信息。同样我们也采用了 Nagle算法,该算法可以保证在速率较低的网络上,若干输入字节以单个TCP报文段传输。另外,服务器和客户之间还可以互相发送命令。

  2. 流量控制

    默认情况下,流量控制是由Rlogin的客户进程完成的。客户进程能够识别用户键入的STOP和START的ASCII字符(Control_S和Control_Q),并且终止或启动终端的输出。

    如果不是这样,每次我们为终止终端输出而键入的Control_S字符将沿网络传输到服务器进程,这时服务器进程将停止往网络上写数据。但是在写操作终止之前,服务器进程可能已经往网络上写了一窗口的输出数据。也就是说,在输出停止之前,成千上万的数据字节还将在屏幕上显示。

    对于一个交互式用户来讲,Control_S字符的响应延时是较大的。

    有时候,服务器的应用程序需要解释输入的每个字节,但又不想让客户对它的输入内容进行处理。解决这个问题的办法就是由服务器告诉客户是否要进行流量控制。

  3. 客户的中断键

    当我们为中断服务器正在运行的进程而键入一个中断字符时(通常是DELETE或Control_C),会发生和流量控制相同的问题。在一条TCP连接的管道上,从服务器进程向客户进程正在发送大量的数据,而客户进程同时在向服务器进程传输中断字符。而我们的本意是要中断字符尽快终止某个进程,使屏幕上不再有任何响应输出。

    在流量控制和中断键这两种情况中,流量控制机制很少终止客户进程到服务器进程的数据流。这个方向仅仅包含我们键入的字符。所以对于从客户输出到服务器的特殊输入字符(Control_S和中断字符)不需要采用 TCP的紧急方式(urgent mode)。

  4. 窗口大小的改变

    如果是窗口风格的显示方式,当应用程序在运行的时候,我们还可以动态地改变窗口的大小。一些应用程序(典型的如那些操作整个窗口的应用程序,如全屏编辑器)需要知道窗口大小的变化。目前大多数Unix系统提供这种功能,可以告诉应用程序关于窗口大小的变化。

    对于远程登录这种情况,窗口大小的变化发生在客户端,而运行在服务器端的应用程序需要知道窗口大小变化。所以Rlogin的客户需要采用某些方法来通知服务器窗口大小变化的情况以及新窗口的大小。

  5. 服务器到客户的命令

    当服务器要给客户发送命令时,服务器就进入紧急方式,并且把命令放在紧急数据的最后一个字节中。当客户进程收到这个紧急方式通知时,它从连接上读取数据并且保存起来,直到读到命令字节(即紧急数据的最后一个字节)。这时候客户进程根据读到的命令,再决定对于所读到并保存起来的数据是显示在终端上还是丢弃它。下图介绍了这4个命令:

    采用TCP紧急方式发送这些命令的一个原因是第一个命令(“清仓输出(flush output)”)需要立即发送给客户,即使服务器到客户的数据流被窗口流量控制所终止。这种情况下,即服务器到客户的输出被流量控制所终止的情况是经常发生的,这是因为运行在服务器的进程的输出速率通常大于客户终端的显示速率。另一方面,客户到服务器的数据流很少被流量控制所终止,因为这个方向的数据流仅仅包含用户所键入的字符。

  6. 客户到服务器的命令

    对于客户到服务器的命令,只定义了一条命令,那就是:将当前窗口大小发送给服务器。当客户的窗口大小发生变化时,客户并不立即向服务器报告,除非收到了服务器发来的0x80命令。

    由于只存在一条TCP连接,客户必须对在连接上传输的该命令字节进行标注,使得服务器可以从数据流中识别出命令,而不是把它发送到上层的应用程序中去。处理的方法就是在两个字节的0xff后面紧跟着发送两个特殊的标志字节。

    对于窗口大小命令,两个标志字节是ASCII码的字符‘s’。之后是4个16bit长的数据(按网络字节顺序),分别是:行数(例如,25),每列的字符数(例如,80),X方向的像素数量,Y方向的像素数量。通常情况下,后两个16bit是0,因为在Rlogin服务器进程调用的应用程序中,通常是以字符为单位来度量屏幕的,而不是像素点。

    上面我们介绍的从客户进程到服务器进程的命令采用带内信令( in-band signaling),这是因为命令字节和其他的普通数据一起传输。选择0xff字节来表示这个带内信令的原因是:一般用户的操作不会产生0xff这个字节。所以说Rlogin是不完备的。

    由于大多数的API采用的技术叫做“带外数据(out-of-band data)”,所以我们就称它为带外信令 (out-of-band signaling)。

    既然带内信令被用来传输从客户到服务器的命令,那么服务器进程必须检查从客户进程收到的每个字节,看看是否有两个连续的0xff字节。但是对于采用带外信令的、从服务器传输到到客户的命令,客户进程不需要检查收到的每个字节,除非服务器进程进入了紧急方式。即使在紧急方式下,客户进程也仅仅需要留意紧急指针所指向的字节。而且由于从客户进程到服务器的数据流量和相反方向的数据流量之比是1:20,这就暗示带内信令适合于数据量比较小的情况(从客户到服务器),而带外信令适合于数据量比较大的情况(从服务器到客户)。

  7. 客户的转义符

    想要和Rlogin客户进程直接通信,方法是在一行的开头键入代字符(tilde )“~”,紧跟着是下列4个字符之一:

    1. 以一个句号结束客户进程。
    2. 以文件结束符(通常是Control_D)结束客户进程。
    3. 以任务控制挂起符(通常是Control_Z)挂起客户进程。
    4. 以任务控制延迟挂起符(通常是Control_Y)来挂起仅仅是客户进程的输入。

    这时,不管客户运行什么程序,键入的任何信息将由该程序进行解释,但是从服务器发送到客户的信息还是输出到终端上。这非常适合当我们需要在服务器上运行一个长时间程序的场合,我们既想知道该程序的输出结果,同时还想在客户上运行其他程序。

    只有当客户进程的Unix系统支持任务控制时,后两个命令才有效。

Telnet协议

Telnet协议可以工作在任何主机或任何终端之间。官方定义了一种通用字符终端叫做网络虚 拟终端NVT(Network Virtual Terminal)。NVT是虚拟设备,连接的双方,即客户机和服务器, 都必须把它们的物理终端和NVT进行相互转换。也就是说,不管客户进程终端是什么类型, 操作系统必须把它转换为NVT格式。同时,不管服务器进程的终端是什么类型,操作系统必 须能够把NVT格式转换为终端所能够支持的格式。

NVT是带有键盘和打印机的字符设备。用户击键产生的数据被发送到服务器进程,服务
器进程回送的响应则输出到打印机上。默认情况下,用户击键产生的数据是发送到打印机上
的,但是我们可以看到这个选项是可以改变的。

  1. NVT ASCII

    术语NVT ASCII代表7比特的ASCII字符集,网间网协议族都使用NVT ASCII。每个7比特的字符都以8比特格式发送,最高位比特为 0。

    行结束符以两个字符CR(回车)和紧接着的LF(换行)这样的序列表示。以\r\n来表示。单独的一个CR也是以两个字符序列来表示,它们是CR和紧接着的NUL(字节0),以\r\0表示。

  2. Telnet命令

    Telnet通信的两个方向都采用带内信令方式。字节0xff(十进制的255 )叫做 I A C(interpret as command,意思是“作为命令来解释”)。该字节后面的一个字节才是命令字节。
    如果要发送数据255,就必须发送两个连续的字节255(在前面一节中我们讲到数据流是NVT ASCII,它们都是7bit的格式,这就暗示着255这个数据字节不能在Telnet上传输。)

    下图列出了当前一个字节是IAC(255)时所有的Telnet命令:

  3. 选项协商

    虽然我们可以认为Telnet连接的双方都是NVT,但是实际上Telnet连接双方首先进行交互的信息是选项协商数据。选项协商是对称的,也就是说任何一方都可以主动发送选项协商请求给对方。

    对于任何给定的选项,连接的任何一方都可以发送下面 4种请求的任意一个请求。

    1. WILL : 发 送 方 本 身 将 激 活(enable )选项。
    2. DO :发送方想叫接收端激活选项。
    3. WONT :发送方本身想禁止选项。
    4. DON’T:发送方想让接收端去禁止选项。

    由于Telnet规则规定,对于激活选项请求(如 1和2),有权同意或者不同意。而对于使选项失效请求(如 3和4),必须同意。这样,4种请求就会组合出6种情况,如下图所示:

    选项协商需要3个字节:一个IAC字节,接着一个字节是 WILL, DO, WONT和DONT这四者之一,最后一个ID字节指明激活或禁止选项。现在,有4 0多个选项是可以协商的。 Assigned Number RFC文档中指明选项字节的值,并且一些相关的RFC文档描述了这些选项。

    Telnet的选项协商机制和Telnet协议的大部分内容一样,是对称的。连接的双方都可以发起选项协商请求。但我们知道,远程登录不是对称的应用。客户进程完成某些任务,而服务器进程则完成其他一些任务。下面我们将看到,某些Telnet选项仅仅适合于客户进程(例如要求激活行模式方式),某些选项则仅仅适合于服务器进程。

  4. 子选项协商

    有些选项不是仅仅用“激活”或“禁止”就能够表达的。指定终端类型就是一个例子,客户进程必须发送用一个 ASCII字符串来表示终端类型。为了处理这种选项,我们必须定义子选项协商机制。

    首先连接的某一方(通常是客户进程)发送 3个字节的字符序列来请求激活该选项。

    <IAC, WILL, 24>

    这里的24(十进制)是终端类型选项的ID号。如果收端(通常是服务器进程)同意,那么响应数据是:

    <IAC, DO, 24>

    然后服务器进程再发送如下的字符串:

    <IAC, SB, 24, 1, IAC, SE>

    该字符串询问客户进程的终端类型。其中SB是子选项协商的起始命令标志。下一个字节的“24”代表这是终端类型选项的子选项(通常SB后面的选项值就是子选项所要提交的内容)。下一个字节的“ 1”表示“发送你的终端类型”。子选项协商的结束命令标志也是IAC,就像SB是起始命令标志一样。

    如果终端类型是ibmpc,客户进程的响应命令将是:

    <IAC, SB, 24, 0‘I’, ‘B’, ‘M’, ‘P’, ‘C’, IAC, SE>

    第4个字节“0”代表“我的终端类型是”。在Telnet子选项协商过程中,终端类型用大写表示,当服务器收到该字符串后会自动转换为小写字符。

  5. 半双工、一次一字符、一次一行或行方式

    对于大多数Telnet的服务器进程和客户进程,共有 4种操作方式。

    1. 半双工

      这是Telnet的默认方式,但现在却很少使用。NVT默认是一个半双工设备,在接收用户输入之前,它必须从服务器进程获得 GO AHEAD(G A)命令。用户的输入在本地回显,方向是从NVT键盘到NVT打印机,所以客户进程到服务器进程只能发送整行的数据。

      虽然该方式适用于所有类型的终端设备,但是它不能充分发挥目前大量使用的支持全双工通信的终端功能。

    2. 一次一个字符方式

      这和的Rlogin工作方式类似。我们所键入的每个字符都单独发送到服务器进程。服务器进程回显大多数的字符,除非服务器进程端的应用程序去掉了回显功能。

      该方式的缺点也是显而易见的。当网络速度很慢,而且网络流量比较大的时候,那么回显的速度也会很慢。虽然如此,但目前大多数Telnet实现都把这种方式作为默认方式。

      如果要进入这种方式,只要激活服务器进程的 SUPPRESS GO AHEAD选项即可。这可以通过由客户进程发送 DO SUPPRESS GO AHEAD(请求激活服务器进程的选项)请求完成,也可以通过服务器进程给客户进程发送 WILL SUPPRESS GO AHEAD(服务器进程激活选项)请求来完成。服务器进程通常还会跟着发送 WILL ECHO,以使回显功能有效。

    3. 一次一行方式

      该方式通常叫做准行方式( kludge line mode),该方式的实现是遵照 RFC 858的。如果要实现带远程回显的一次一个字符方式,ECHO选项和SUPPRESS GO AHEAD选项必须同时有效。准行方式采用这种方式来表示当两个选项的其中之一无效时,Telnet就是工作在一次一行方式。

    4. 行方式

      我们用这个术语代表实行方式选项,这是在 RFC 1184中定义的。这个选项也是通过客户进程和服务器进程进行协商而确定的,它纠正了准行方式的所有缺陷。目前比较新的Telnet实现支持这种方式。

  6. 同步信号

    Telnet以Data Mark命令(即DM)作为同步信号,该同步信号是以TCP紧急数据形式发送的。 DM命令是随数据流传输的同步标志,它告诉收端回到正常的处理过程上来。Telnet的双方都可以发送该命令。

    当一端收到对方已经进入了紧急方式的通知后,它将开始读数据流,一边读一边丢弃所读的数据,直到读到Telnet命令为止。紧急数据的最后一个字节就是DM字节。采用TCP紧急方式的原因就是:即使TCP数据流已经被TCP流量控制所终止,Telnet命令也可以在连接上传输。

  7. 客户的转义符

    和Rlogin的客户进程一样,Telnet客户进程也可以使用户直接和客户进程进行交互,而不是被发送到服务器进程。通常客户的转义字符是Control _ ](control键和右中括号键,通常以“^ ]”表示)。这使得客户进程显示它的提示符,通常是“ telnet>”。这时候有很多命令可供用户选择,以改变连接的特性或打印某些信息。大多数的Unix客户进程提供“ help”命令,该命令将显示所有可用的命令。

Telnet举例

  1. 单字符方式

    单字符方式类似于Rlogin。用户在终端输入的每个字符都将由终端发送到服务器进程,服务器进程的响应也将以字符方式回显到终端上。

  2. 行方式

    一旦登录完成,客户进程将把数据以整行的方式发送给服务器进程。这就是行方式选项的目的。行方式大大地减少了客户进程和服务器进程之间的数据交互数量,而且对于用户的按键(也就是回显和编辑)提供更快的响应。

    在和Rlogin中输入同样的命令进行比较,我们看到在Telnet行方式下只需要 2个报文段(一个包含数据,另一个用于ACK,连同IP和TCP首部共 86字节),而在Rlogin中要发送15个报文段(5个有键入的数据,5个有回显的数据,5个是ACK,共611字节)。可见节省的数据量是非常可观的。

    如果在服务器端运行一个需要进入单个字符方式的应用程序(如vi编辑器),会产生如下交互:

    1. 当服务器的应用程序启动了,并改变其伪终端方式时,Telnet服务器进程被通告需要进入单个字符方式。然后服务器发送 WILL ECHO命令和行方式子选项,以告知客户不要再以行方式工作,转而进入单个字符方式。
    2. 客户响应以DO ECHO,并确认行方式子选项。
    3. 应用程序在服务器上运行。我们键入的每个字符将发送到服务器(当然要强制使用Nagle算法),此时服务器将处理必要的回显工作。
    4. 当应用程序终止时,就恢复其伪终端方式,并通告Telnet服务器。服务器将向客户发送WONT ECHO命令,同时发送行方式子选项,告诉客户恢复进入行方式。
    5. 客户响应DONT ECHO,确认进入行方式。

    上述情况同我们键入口令之间的区别表明:回显功能和单个字符方式与一次一行方式没有依赖关系。当我们键入口令时,回显功能必须失效,但一次一行方式有效。对于一个全屏应用来讲,例如编辑器,回显必须失效而单个字符方式必须有效。

  3. 一次一行方式(准行方式)

    如果客户不支持行方式,那么较新的服务器支持行方式选项,它也将转入准行方式 (Kludge line mode)。当所有的客户进程和服务器进程都支持准行方式,但它不是默认方式,必须由客户进程或用户特地激活它。

    如果在服务器端运行如vi编辑器这样的应用程序,同样会有行方式下遇到的问题。当要运行这样的应用程序时,服务器进程必须告诉客户进程从准行方式切换到单字符方式。当应用程序结束时,必须告诉客户进程返回到准行方式。下面是这个过程需要用到的技术要点。

    1. 当应用程序改变其伪终端方式并通知服务器进程时,服务器进程将进入单字符方式。服务器进程向客户进程发送 WILL SUPPRESS GO AHEAD和WILL ECHO,这将使客户进程进入单字符方式。
    2. 客户进程回送DO SUPPRESS GO AHEAD和WILL ECHO。
    3. 应用程序开始在服务器端运行。
    4. 当应用程序结束并改变其伪终端方式时,服务器进程发送WONT SUPPRESS GO AHEAD和WONT ECHO命令,使得客户进程返回准行方式。
    5. 客户进程回送DONT SUPPRESS GO AHEAD和DONT ECHO命令,告诉服务器进程它已经回到了准行方式。
上一篇:
TCP/IP详解 卷一 FTP:文件传输协议
下一篇:
TCP/IP详解 卷一 SNMP:简单网络管理协议