WILL提出第一方能够和原意执行的选项。如果第一方应该开始执行那个选项,则另一方回复 D0,如果另一方无法理解或不支持该选项,则回复 DONT。DO告诉另一方开始执行选项。如果另一方开始执行选项,则回复 WILL,如果另一方无法理解或不支持该选项,则回复 WONT。
我们最小的客户端将只处理 4 条命令:WILL、WONT、DO 和 DONT,以及两个选项:TERMINAL_TYPE(24)和 NAWS(“协商窗口大小” 31)。对于所有其他选项,我们将返回 DONT 或 WONT。(我曾考虑支持 RANDOMLY_LOSE_DATA(256)和 SUBLIMINAL_MESSAGE(257)选项,但是我们现在尽量保持其简单。)
Telnet 输入流
要查看以代码表示的协议,可以看看 TelnetInputStream.java 的清单。最令人兴奋的是 read() 方法。在这个摘录中,我去除了某些细节:
public int read() throws IOException
{
byte b;
b = (byte) input.read();
if ( b != IAC ) return b; // not an IAC, skip.
b = (byte) input.read();
if ( b == IAC ) return b; // two IACs isn't.
if ( b != SB ) // handle command
{
switch ( b )
{
// basic commands
case GA:
case NOP:
case DAT:
case BRK:
case IP:
case AO:
case AYT:
case EC:
case EL:
// not implemented: ignore for now
System.err.println(
"Ignored command: "
+ b + " : " + reply[2] );
return read();
// option prefixes
case DO:
case DONT:
case WILL:
case WONT:
// read next byte to determine option
reply[2] = (byte) input.read();
switch ( reply[2] )
{
case TERMINAL_TYPE:
...
case WINDOW_SIZE:
...
default:
// unsupported option: break
...
}
break;
default:
// unsupported option: suppress and exit
System.err.println(
"Unsupported command: " + b );
}
}
else // handle begin-sub
{
b = (byte) input.read();
reply[2] = b;
switch ( b )
{
case TERMINAL_TYPE:
...
default:
reply[1] = WONT;
write( reply );
}
}
return read();
}
|
因为我们忽略了所有的内容而只留下协商命令和多数选项,所以当我们接收到针对 TERMINAL_TYPE 或 NAWS 的 D0 命令时,感兴趣的部分才开始了。
对于 TERMINAL_TYPE,我们设法对我们和另一端都支持哪种传统的终端达成一致意见。某些基于终端的应用程序将利用更高级终端类型的特性,如颜色、粗体和下划线。更为复杂的终端模拟器将模拟多种终端类型,如 ansi、vt100 和 vt102。协商就是设法建立最佳的共同点。最简单的终端类型称为哑终端,这也是我们将支持的一种。
如果我们接收到 IAC DO TERMINAL_TYPE,我们用 IAC WILL TERMINAL_TYPE 响应。依照 RFC 1091 规范,然后远程主机就开始与 IAC SB TERMINAL_TYPE TERMINAL_SEND IAC SE 的子协商,然后我们响应 IAC SB TERMINAL_TYPE TERMINAL_IS d u m b IAC SE。
...
case TERMINAL_TYPE:
...
reply[1] = SB;
write( reply );
char[] c = terminal.toCharArray();
byte[] bytes = new byte[c.length+3];
int i = 0;
bytes[i++] = TERMINAL_IS;
for ( ; i < c.length+1; i++ )
{
bytes[i] = (byte) c[i-1];
}
bytes[i++] = IAC;
bytes[i++] = SE;
write( bytes );
break;
...
|