TELNET ,最近一直都在困扰着我的大问题,可以说是我们最近在做的自动安装模块的核心功能,使用telnet做远程控制,开始还觉得挺简单的,网上一搜,就搜到了好多telnet的例子,其中大部分用的都是基于apache的common-net中的telnetclient写的例子,于是我们就也用了,因为我们做的自动安装要跨操作系统,因此不仅仅有windows还有linux更有unix,但是从网上找到的例子大部分都是基于某个平台的。
还有当我们在开发时遇到的另外两个问题,分别是如何判断执行的命令何时结束以及telnet终端的问题。围绕着这两个问题我可谓是不断的改写telnet基础类从common-net到自己写telnet实现再到common-net,再到jtelnet,最后jtelnet和common-net融合实现vt100终端实现,可谓是一波三折。下面还是先说下telnet协议吧,注意要把telnet协议和终端类型给分开,telnet只是利用到了终端类型而已,而终端类型本身并不属于telnet协议本身。
telnet协议
Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议。Telnet协议的目的是提供一个相对通用的,双向的,面向八位字节的通信方法,允许界面终端设备和面向终端的过程能通过一个标准过程进行互相交互。应用Telnet协议能够把本地用户所使用的计算机变成远程主机系统的一个终端。
由于telnet是跨操作系统的,考虑到操作系统之间可能存在某些命令差异,比如windows和linux换行差别以及终止命令执行命令等等,因此为了适应异构系统,Telnet协议定义了数据和命令在Internet上的传输方式,此定义被称作网络虚拟终端NVT(Net Virtual Terminal)来转换输入的命令和输出的结果为相应的格式在网络上传输。这种格式有很多,其中常见的有VT100,VT220,ANSI等等。
由于Telnet两端的机器和操作系统的异构性,使得Telnet不可能也不应该严格规定每一个telnet连接的详细配置,否则将大大影响Telnet的适应异构性。因此,Telnet采用选项协商机制来解决这一问题。
Telnet选项的范围很广:一些选项扩充了大方向的功能,而一些选项制涉及一些微小细节。例如:有一个选项可以控制Telnet是在半双工还是全双工模式下工作(大方向);还有一个选项允许远地机器上的服务器决定用户终端类型(小细节)。
Telnet选项的协商方式也很有意思,它对于每个选项的处理都是对称的,即任何一端都可以发出协商申请;任何一端都可以接受或拒绝这个申请。另外,如果一端试图协商另一端不了解的选项,接受请求的一端可简单的拒绝协商。
说到底,telnet本身是由3部分组成的,NVT终端,选项协商和子选项协商。
1、NVT终端:
TELNET使用了一种对称的数据表示,当每个客户机发送数据时,把它的本地终端的字符表示影射到NVT的字符表示上,当接收数据时,又把NVT的表示映射到本地字符集合上。
在通信开始时,通信双方都支持一个基本的NVT终端特性子集(只能区分何为数据,何为命令),以便在最低层次上通信,在这个基础上,双方通过NVT命令协商确定NVT的更高层次上的特性,实现对NVT功能的扩展。
在TELNET中存在大量的子协议用于协商扩展基本的网络虚拟终端NVT的功能,由于终端类型的多样化,使得TELNET协议族变得庞大起来。
在网络虚拟终端NVT上传输的数据采用8bit字节数据,其中最高位为0的字节用于一般数据,最高位为1的字节用于NVT命令。
2、选项协商
TELNET的操作协商使用NVT命令,即最高位为1的字节流,每条NVT命令以字节IAC(0xFF)开始。原理如下:
只要客户机或服务器要发送命令序列而不是数据流,它就在数据流中插入一个特殊的保留字符,该保留字符叫做“解释为命令”(IAC ,Interpret As Command) 字符。当接收方在一个入数据流中发现IAC字符时,它就把后继的字节处理为一个命令序列。下面列出了所有的Telnet NVT命令
。表1 TELNET 命令
名称 |
编码 |
说明 |
EOF |
236 |
文件结束符 |
SUSP |
237 |
挂起当前进程 |
ABORT |
238 |
中止进程 |
EOR |
239 |
记录结束符 |
SE |
240 |
子选项结束 |
NOP |
241 |
空操作 |
DM |
242 |
数据标记 |
BRK |
243 |
终止符(break) |
IP |
244 |
终止进程 |
AO |
245 |
终止输出 |
AYT |
246 |
请求应答 |
EC |
247 |
终止符 |
EL |
248 |
擦除一行 |
GA |
249 |
继续 |
SB |
250 |
子选项开始 |
WILL |
251 |
选项协商 |
WONT |
252 |
选项协商 |
DO |
253 |
选项协商 |
DONT |
254 |
选项协商 |
IAC |
255 |
字符0XFF |
其中常用的TELNET选项协商如下:
那么对于接收方和发送方有以下几种组合:
表2 TELNET 选项协商的六种情况
发送者 |
接收者 |
说明 |
WILL |
DO |
发送者想激活某选项,接受者接收该选项请求 |
WILL |
DONT |
发送者想激活某选项,接受者拒绝该选项请求 |
DO |
WILL |
发送者希望接收者激活某选项,接受者接受该请求 |
DO |
DONT |
发送者希望接收6者激活某选项,接受者拒绝该请求 |
WONT |
DONT |
发送者希望使某选项无效,接受者必须接受该请求 |
DONT |
WONT |
发送者希望对方使某选项无效,接受者必须接受该请求 |
选项协商需要3个字节:IAC,然后是WILL、DO、WONT或DONT;最后一个标识字节用来指明操作的选项。常用的选项代码如下:
表3 TELNET 选项代码
选项标识 |
名称 |
RFC |
1 |
回应(echo) |
857 |
3 |
禁止继续 |
858 |
5 |
状态 |
859 |
6 |
时钟标识 |
860 |
24 |
终端类型 |
1,091 |
31 |
窗口大小 |
1,073 |
32 |
终端速率 |
1,079 |
33 |
远端流量控制 |
1,372 |
34 |
行模式 |
1,184 |
36 |
环境变量 |
1,408 |
通常情况下,客户机向服务器发送字符而服务器将其回显到用户的终端上,但是,如果网络的时延回引起回显速度太慢,用户可能更愿意让本地系统回显字符。在客户机允许本地系统回显前,它要向服务器发送以下序列:
IAC DONT ECHO
服务器收到请求后,发出3个字符的响应:
IAC WONT ECHO
表示服务器已经按请求同意关闭回显。
3、子选项协商
除了“打开”或“关闭”以外,有些选项还需要更多的信息,例如对于指明终端类型来说,客户必须发送一个字符串来标识终端类型,所以要定义子选项协商。
RFC 1091定义了终端类型的子选项协商。举个例子:
客户发送字节序列来请求打开选项:
< IAC,WILL,24>
24是终端类型的选项标识符。如果服务器同意该请求,响应为:
< IAC,DO,24 >
接着服务器发送
< IAC,SB,24,1,IAC,SE>请求客户给出其终端类型。
SB是子选项开始命令,下一个字节24表示该子选项为终端类型选项。下一个字节1表示:发送你的终端类型。客户的响应为:
< IAC,SB,24,0,'I','B','M','P','C', IAC,SE>
第四个字节0的含义是“我的终端类型为”。
除了终端类型为还有一个常用的子选项,那就是窗口大小。
由Telnet客户端发送,通知Telnet服务器端这个窗口的宽度和高度。窗口尺寸信息从Telnet客户端到Telnet服务器端通过这个选项来传递。此信息是参考性的。服务器可能接受这个选项,但是并不使用传递的信息。
客户端和服务器端使用标准的Telnet WILL/DO/DON'T/WON'T机制来协商发送窗口尺寸信息。如如果以后客户端的窗口尺寸改变了(例如,窗口尺寸被用户改变),客户端可能再次发送这个子果客户端和服务器端都同意,客户端可以发送一个子协商用来传递窗口的尺寸协商。因为在某些操作系统上,服务器正在执行的时候可能不允许更新窗口尺寸信息,所以服务器可能在接受最初的窗口尺寸后发送一个DON'T NAWS给客户端以阻止更多的子协商。一个协商循环将不会形成下面这些规则。
子协商包含两个值,用字符表示的窗口的宽度值和高度值。这两个值中的每一个值都是以两个字节为一组以标准的Internet字节和比特顺序发送的。这就允许窗口的宽度或高度的最大值是65535个字符。对于宽度或高度来说,接受一个等于零的值就意味着没有字符宽度或高度被发送。既然如此,Telnet服务器将假定宽度或高度是与操作系统相关的(它将有可能是基于终端类型信息的,这个终端类型信息是使用TERMINAL TYPE的Telnet选项来发送的)。
子协商的语法是
IAC SB NAWS WIDTH[1] WIDTH[0] HEIGHT[1] HEIGHT[0] IAC SE
IAC SB NAWS <16-bit value> <16-bit value> IAC SE
1). 服务器建议,客户端同意使用NAWS
(服务器发送)IAC DO NAWS
(客户端发送)IAC WILL NAWS
(客户端发送)IAC SB NAWS 0 80 0 24 IAC SE
[窗口80字符宽,24字符高]
[某个时刻用户改变了窗口尺寸]
(客户端发送)IAC SB NAWS 0 80 0 64 IAC SE
[窗口80字符宽,64字符高]
所有的数字形式
(服务器发送)255 253 31
(客户端发送)255 253 31
(客户端发送)255 250 31 0 80 0 24 255 240
(客户端发送)255 250 31 0 80 0 64 255 240
2).客户端建议,服务器同意使用NAWS
(客户端发送)IAC WILL NAWS
(服务器发送)IAC DO NAWS
(客户端发送)IAC SB NAWS 1 44 0 24 IAC SE
[窗口300字符宽,24字符高]
3). 客户端建议,服务器拒绝使用NAWS
(客户端发送)IAC WILL NAWS
(服务器发送)IAC DON'T NAWS
4). 服务器建议,客户端拒绝使用NAWS
(服务器发送)IAC DO NAWS
(客户端发送)IAC WON'T NAWS