MIDP终端模拟之一:一个简单的模拟器MIDlet[3]

[入库:2006年2月23日] [更新:2007年3月24日]

本文简介:


注意,因为 telnet 采取 8 位的 ASCII 字符,而 Java 的字符是 16 位 Unicode,在发送前,我们必须注意将终端类型字符串的每个 Unicode 字符转换成 ASCII 字节。这个转换在几乎所有的 internet 协议中都是必需的,特别是早期协议。我们可以在对 String.getBytes() 的调用中指定 ASCII 编码,但由于这是非常简单的转换,我们可以内部完成它。虽然 MIDP 规范规定了要支持哪种字符编码,但不同的实现程序有时会出错,安全一些总比说抱歉要好。

在“协商窗口大小”(NAWS)情况下,我们只是简单地将屏幕尺寸通知给远程主机。终端应该使用等宽字体,所以屏幕是一个字符网格,具有固定的行数和列数。如果我们知道了屏幕的尺寸以及服务器支持 NAWS 选项,我们就可以在连接时发送屏幕的尺寸,并且如果屏幕尺寸改变了,以后可以再次发送。

正如 RFC 1073 规范所推荐的,当我们接收到 IAC DO NAWS 后,我们响应 IAC WILL NAWS,然后立即发送我们的当前屏幕尺寸。因为有时要求大于 255 的屏幕高度和宽度,所以宽度和高度分别作为两字节的整数发送:先是高位字节,然后是低位字节。这样我们发送 IAC SB NAWS width-high-byte width-low-byte height-high-byte height-low-byte IAC SE。代码如下:

    ...
    case WINDOW_SIZE:
        // do allow and reply with window size
        if ( b == DO && width > 0 && height > 0 )
        {
            reply[1] = WILL;
            write( reply );
            reply[1] = SB;
            write( reply );
            byte[] bytes = new byte[6];
            bytes[0] = (byte) (width >> 8);
            bytes[1] = (byte) (width & 0xff);
            bytes[2] = (byte) (height >> 8);
            bytes[3] = (byte) (height & 0xff);
            bytes[4] = IAC;
            bytes[5] = SE;
            write( bytes );
            break;
        }
    ...

在编写用户界面和知道窗口的宽度和高度之前,我们不能使用该代码。目前,我们只是简单地发送 IAC WONT NAWS

对于可用性而言,如果我们的类所需要做的所有工作就是从 InputStream 读取数据,那么类会很简洁。但是,我们还需要把数据送回服务器,所以我们需要 OutputStream 用于写入。因为我们支持终端类型和窗口尺寸选项,所以我们还需要所有这些传递给构造函数的信息。为了方便,我们使用了第二个构造函数,它只获取输入和输出流,默认的终端类型是“哑”终端,窗口高度和宽度是 0。

Telnet 输出流

与 telnet 输入流相比,TelnetOutputStream 可是很轻松的事。记住,虽然我们的应用程序可自由写入 255,就像其他任意数值一样,但是远程主机上的 telnet 服务器会尝试将其解释为 IAC,并且接着会查找命令代码。因此输出流的惟一职责是在其写入时注意具有值 255 的字节,如果有则再用一个 255 将其转义。

在这个 TelnetOutputStream.java 的摘录中,您可以看到这个任务与听起来一样简单:

    ...
    private OutputStream output;
    private final static byte[] ESCAPED = 
        { (byte) 255, (byte) 255 };
    
    public TelnetOutputStream( OutputStream inOutput )
    {
        output = inOutput;
    }
    
    public void write( int b ) throws IOException
    {
        if ( b == 255 )
        {
            output.write( ESCAPED );
        }
        else
        {
            output.write( b );
        }
    }
    ...

我们分配了一个包含两个字节的静态最终字节数组,目的都是为了避免一次发送一个字节而引起的任何开销,以及避免按需分配数组可能导致的任何开销。对于 MIDP 开发(相对应于 Swing 开发)来说有趣的是,这些细节可能实际上很重要。

Telnet 连接

因为 TelnetOutputStream 需要一个 OutputStream,且 TelnetInputStream 同时需要一个 InputStream  和一个与 TelnetOutputStream 分离的 OutputStream,所以在设置 telnet 会话时要注意很多东西。因为 MIDP 程序员习惯于使用 GCF,我们可以为面向对象的目的而将我们的类包装到更加用户友好的软件包中,从而隐藏了复杂性并与熟悉的使用模式保持一致。TelnetConnection.java 向您展示了如何做。您所需做的就是将您的 StreamConnection 传递到构造器,所以建立一个 telnet 会话就像这样:

    ...
    StreamConnection connection;

    connection = (StreamConnection)
        Connector.open("socket://wunderground.com:3000" ),
                       Connector.READ_WRITE, true );
    connection = new TelnetConnection( connection );

    InputStream input = connection.openInputStream();
    OutputStream output = connection.openOutputStream();
    ...

本文关键:MIDP终端模拟之一:一个简单的模拟器MIDlet
  相关方案
Google
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top