Java による授業向け画面共有システムの設計と実装
大城 信康 谷成 雄
目的と背景
大学の講義中、スクリーンに映されている画面は後ろの席程見えずらい。
その問題を手元のPCにも写せるようにすることで解決しようと考えた。
60人以上での画面共有を行うことを目標とする。
VNCを用いての画面共有
画面を共有する方法 -> VNC
VNC: Virtual Network Computing ネットワークを介してコンピュータを遠隔操作するプログラム
VNCのリモートPCの画面を写す機能を利用する。
通常のVNCの問題点
|
VNC Serverの負荷が重い。
Server側の通信網1本への通信負荷が高い。
|
通常のVNCの問題点
1台と48台でVNCをかけた時のスループットとサーバ側のCPU使用率
|
スループット(単位:Byte) |
CPU使用率 |
1台 |
20M |
15% |
48台 |
0.4M |
100% |
VNCに使われるCPUの使用率が100%になり、スループットが5分の1まで下がっている。
VNCの問題点の解決策
クライアントを木構造で接続させる
TreeVNCの利点
クライアントが増えてもかかる負荷一定。
通信網1本に対する負荷が減り、安定した通信ができる(有線)。
通常のVNC |
TreeVNC |
|
|
TreeVNCの設計
TreeVNCのクライアントは最初にTop Proxyに接続を行う。
データは木の下へと流していく。
tightVNC ViewerのJava版(ver 1.3)を元にTreeVNCの実装を行う。
発表内容
- RFB Protocol
- データ量の見積もり
- データ転送に用いたMulticastQueueについての説明
- TreeVNCのデモ
- 木構造の再構築
- ZRLE Encodingの問題
RFB protocol
Remote Frame Buffer Protocol :
GUI操作によるリモートアクセス用の通信プロトコル。VNCで用いられる。
転送される画面(フレームバッファ)のデータは変更があった部分(差分)だけが矩形単位で送られる。
□ で囲まれている矩形のデータだけが送られてくる。
VNC のシーケンス図
|
1~5まではinitial seaquenceとなる。
6以降は繰り返し行われる処理。画面のデータが転送されてくる。
|
RFB Protocol
FramebufferUpdateRequestの内容
バイト数 |
型 [値] |
説明 |
1 |
U8 3 |
message-type |
1 |
U8 |
incremental |
2 |
U16 |
x-position |
2 |
U16 |
y-position |
2 |
U16 |
width |
2 |
U16 |
height |
|
incrementalについて
0の場合、VNC Serverは指定された領域の矩形データを送ってくる。
0以外の場合はその領域内で差分が発生した時に矩形データを送る。
|
RFB Protocol
FramebufferUpdate
バイト数 |
型 [値] |
説明 |
1 |
U8 0 |
message-type |
1 |
U8 |
padding |
2 |
U16 |
number-of-rectangles |
以下number-of-rectanglesの数だけ矩形のデータが続く
2 |
U16 |
x-position |
2 |
U16 |
y-position |
2 |
U16 |
width |
2 |
U16 |
height |
4 |
U32 |
encoding-type |
|
RFB Protocol
図を入れる
指定された領域の矩形を更新しているのが分かる図
RFB Protocol
RFB ProtocolにはFramebufferUpdateRequestだけではなく、キーボード・マウスポインタの入力を伝えるkeyEventやPointerEvent等もある。
TreeVNCでは画面の共有を行いたいのでそれらのイベントに対しての実装は行っていない。
負荷分散
負荷分散を行う上で重要: -> 転送するデータ量を見積もること
ネットワークの帯域やswtichにかかる負荷を把握するため。負荷を把握していないと負荷分散できているかどうかも解らない。
RFB Protocolで送られてくるデータ量: -> 先頭の20バイトを読むことで見積もることができる。
データ量の見積もり
FramebufferUpdate(以下update)毎にデータを扱うためには、update1回分で送られてくるバイト量を知る必要がある
(どこまで読みこめば終わりなのか知る必要がある)。
先頭の20バイトを読むことでupdate1回分のバイト量を知ることができる(厳密にはエンコード次第だが...)。
updateは最初に送られてくる情報に矩形の横と縦幅(width,height)が含まれていてそれと扱われるエンコードによって全体のデータ量を計算することができる。
データ量の見積もり
ZRLEエンコードの場合
最初の4bitにどれだけのデータ量が送られてくるのかという情報が送られてくる。
バイト数 |
型 [値] |
説明 |
4 |
U32 |
length |
length |
U8 array |
zlibData |
データ量の見積もり
先頭20バイトを読みupdate一回分のデータ量を調べる。
update1回分のデータを読み込み次のクライアントに送信する。
また、描画データを送信すると同時に画面の更新を行うようにする。
描画データの管理はMulticastQueueで行った。
MulticastQueue
MulticastQueueはjava.util.CountDownLatchを用いて実装されたクラスである。
クライアントから接続されると、データ転送用のスレッド(sender)が走る。
このスレッドは次に流すデータが来るまでは待機して置かなければならない。そして流すべきデータがくるとまた動き始めなければならない。
このスレッドの待機・解放を行うのがMulticastQueueとなる。
MulticastQueue
MulticastQueueの図を入れる。
接続されてきた時点からデータの送信が始まる。データは読み込まれるまでメモリ上に残っている。
MulticastQueueの問題点
Clientがデータを読み込まないとデータが溜まりメモリを圧迫してしまう。
MulticastQueueの問題点
解決策
TimeOut(TO)スレッドを走らせ、一定の時間データを読み込まなければ代わりにこのTOが読み込むようにする。
TreeVNCのデモ
では実際に動かしてみる。
エンコードの問題
ZRLE : Zlib Run-Length Encoding
データをZlib圧縮扱うエンコーディング。
Macintoshでもこのエンコードは使うことができる。
Rawエンコードより約1/8倍少ないデータ量ですむ。
解凍器(Deflater)は辞書を持っていて、その辞書を元に解凍を行う。
この辞書を吐き出す(flush)する機能がJavaにはなかった。
ZRLEの問題
解凍に必要な辞書を取り出すことができないため、ZRLEのデータはそのまま投げるだけでは正しく解凍されない。
そこで、VNC Serverへ接続するTop ProxyはZRLEで送られてきたデータを毎回新しく圧縮し直すという方法をとった。
一度圧縮し直されたデータはそのまま流すことができる。よってクライアント側では圧縮し直す必要はない。
このエンコードはZRLEE(Economy)として扱うことにした。
TreeVNCの利点と欠点
- ケーブル1本への負荷が減る。一極集中型よりスループットを維持できる。
- 無線を使われると遅くなる。
テスト環境について
CUI版のVNCクライアントを作成
48台あるクラスタでCUI版のクライアントをはしらせてVNCをかけさせる。
最初の1台目と50台めをGUI版のクライアントで接続を行い見比べてみる。
既存のプログラムとの比較
VNC Reflector
- tightVNCの作者が作成したプログラム
- VNC Reflecotrにクライアントが接続することでVNCを行うことができる