2007 年 1 月 12 日 22 時 35 分

クライアントメッセージの流れ


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


これでクライアントメッセージが全て揃ったので、
クライアントの送るメッセージを解析する事ができる。

まず、クライアントメッセージを読み出して、
ClientMessage 実装インスタンスを返すメソッドを作る。
例によって RFBSession クラスに追加しよう。

========== RFBSession#getClientMessage ==========

    private ClientMessage getClientMessage(
            RFBContext context, RFBInputStream in) throws IOException {

        // 1 バイト先読み
        in.mark(1);
        int type = in.readU8();
        in.reset();

        // 上限境界ワイルドカードによる限定
        Class<? extends ClientMessage> messageClass;

        switch (type) {
        case ClientMessage.SET_PIXEL_FORMAT:
            messageClass = SetPixelFormatMessage.class;
            break;
        case ClientMessage.FIX_COLOR_MAP_ENTRIES:
            messageClass = FixColorMapEntriesMessage.class;
            break;
        case ClientMessage.SET_ENCODINGS:
            messageClass = SetEncodingsMessage.class;
            break;
        case ClientMessage.FRAMEBUFFER_UPDATE_REQUEST:
            messageClass = FramebufferUpdateRequestMessage.class;
            break;
        case ClientMessage.KEY_EVENT:
            messageClass = KeyEventMessage.class;
            break;
        case ClientMessage.POINTER_EVENT:
            messageClass = PointerEventMessage.class;
            break;
        case ClientMessage.CLIENT_CUT_TEXT:
            messageClass = ClientCutTextMessage.class;
            break;
        default:
            throw new IOException("unknown client message.");
        }

        return in.readMessage(context, messageClass);

    }

========== end of RFBSession#getClientMessage ==========

クライアントメッセージの読み込みは、
RFBInputStream#readMessage を使えば良いが、
このメソッドは Class 型のインスタンスを要求する。

メッセージ駆動モードに入った後は、
送られるメッセージに規則性がないため、
この時点ではどのメッセージが来るかわからない。

そこで、InputStream#mark を呼び出して位置を記憶し、
readU8 でメッセージの種類だけを先読みする。
そして InputStream#reset を呼び出して位置を戻す。

こうすることでメッセージの種類が分かるので、
後は対応したメッセージの Class を用意し、
改めて RFBInputStream#readMessage を呼び出すと完了となる。

messageClass の型に上限境界ワイルドカードを指定したため、
readMessage を呼び出す際にキャストが全く不要である。

では、RFBSession#processMain を書き換えて、
クライアントメッセージをデバッグ出力するようにしてみよう。

========== RFBSession#processMain ==========

    // メイン処理
    private void processMain(RFBContext context,
            RFBInputStream in, RFBOutputStream out) throws IOException {

        // 初期化
        {
            // (…省略…)
        }

        // メッセージ駆動モードへ
        for (;;) {

            // クライアントからメッセージを受け取り
            ClientMessage message = getClientMessage(context, in);

            // コンソールへ出力
            System.out.println(message);

        }

    }

========== end of RFBSession#processMain ==========

では、実行して RealVNC Viewer で接続してみよう。

まだサーバは何の返事もしないので、
表示される画面は真っ黒のままだが、
画面でキー入力したりマウスを動かしたりすると、
コンソールにごちゃごちゃと情報が表示された。

jp.loafer.rfb.message.client.SetPixelFormatMessage@84ce7a
jp.loafer.rfb.message.client.SetEncodingsMessage@a45536
jp.loafer.rfb.message.client.FramebufferUpdateRequestMessage@164b09c
jp.loafer.rfb.message.client.PointerEventMessage@2b9406
jp.loafer.rfb.message.client.PointerEventMessage@1035079
jp.loafer.rfb.message.client.PointerEventMessage@983d95
jp.loafer.rfb.message.client.PointerEventMessage@f30494
jp.loafer.rfb.message.client.PointerEventMessage@b1cc87
jp.loafer.rfb.message.client.PointerEventMessage@eaf40c
jp.loafer.rfb.message.client.KeyEventMessage@50a649
jp.loafer.rfb.message.client.KeyEventMessage@d507e9
jp.loafer.rfb.message.client.KeyEventMessage@1fa6d18
jp.loafer.rfb.message.client.KeyEventMessage@1049d3
jp.loafer.rfb.message.client.KeyEventMessage@15ed659
jp.loafer.rfb.message.client.KeyEventMessage@14a7a12
jp.loafer.rfb.message.client.KeyEventMessage@9444d1
jp.loafer.rfb.message.client.KeyEventMessage@32060c

toString をオーバライドしていなかったので、
このままではメッセージの内容は分からないが、
ちゃんとメッセージを読めているようだ。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.