view paper/chapter4.tex @ 12:53afd895a367

change chapter4.tex
author Yu Taninari <e085734@ie.u-ryukyu.ac.jp>
date Thu, 23 Feb 2012 22:11:54 +0900
parents 92a06963b6a9
children 6fd4463ca136
line wrap: on
line source

\chapter{TreeVNCの設計}
\label{chap:introduction}
\pagenumbering{arabic}

\section{BroadCast}
後で書く
\section{TreeVNCの設計方針}
まず、多人数が参加している授業でVNCを使う場合に起こる問題は、最初で述べたように、一つのコンピュータに多人数が繋がり、
処理性能が大幅に落ちてしまうところが問題である。

この問題を解決する為に、クライアント同士を接続させ、画面描画のデータを受け取ったクライアントが次のクライアントに
データを流すという方法で画面共有を行う方法を考えた。
画面共有を行っているクライアントが一種のVNCサーバ自体にもなる。

また、クライアント同士の接続はツリー構造で行うことで管理がしやすくなると考えた。
クライアント同士の接続の管理はツリーの一番上にいるPC(Top)で行い(図を入れたい)、このTopだけがVNCサーバへ接続を行うようにする。

今回作成したTreeVNCは、上記の実装でツリー状にクライアントを接続していくように実装を行い画面の共有だけを行うように実装した。

TreeVNCはTightVNCのjava版のビューアを元に作成を行った。実装の細かい内容は以下で説明する。TreeVNCはTightVNCのjava版のビューアを元に作成を行った。


\newpage
\section{木の生成}
今回は、ホストに対しクライアントがツリー状に繋がっていくように実装した。ツリー\\
の構成は以下の手順で行う。
 \begin{enumerate}
  \item クライアントが接続する際、ホストに接続をしているプロキシ(今後このプロ\\
キシのことをTopと記述する)に接続する。
 \item Topはクライアントにどこに接続すれば良いかを知らせる。
 \item クライアントはTopから指定されたノードに接続を行う。
 \end{enumerate}
\subsection{Topの仕事}
Topはjava.util.LinkedListでクライアントの情報を保持している。

TopはtreeBranch(木の分木数)を定数で持っていて
クライアントが接続してくるごとにcounterをインクリメントしていき
LinkedListの(counter - 1)/treeBranche番目に入っている親の情報を
接続してきたクライアントに教えることで木を構成することができる。
\newpage
\section{木の再構成}
\newpage
\section{クライアントとの通信}
TreeVNCは、受け取った画面の描画データをそのまま自分に繋がっている次のクライアン\
トに送信する。
描画データを受け取ったクライントはまた次のクライアントへデータをそのまま送信す\\
る。
内部では、まず受け取った描画データの読み込みを先に行いBytebufferでコピーを行う\\

次にクライアントへの送信と自身のビューアへの描画を並列に行う。

\subsection{FramebufferrUpdate}
RFB プロトコルでの画面の描画の更新は、FramebufferUpdateで行われる。
FramebufferUpdateを受け取ることで画面の再描画が行われる。
FrameBufferUpdateでは、メッセージタイプと画面の矩形の数がまず送られ、
次にx座標、y座標、横幅、縦幅、エンコードのタイプ、描画データが矩形の数だけ送ら\\
れてくる。
描画データはエンコードのタイプに従った方法で送られてくる。

\subsection{MulticastQueue}
画面が更新された際に更新をクライアントに伝えなければならない。ノードが多数ある場合、一人一人に更新を知らせるのではなく、同時に画面の更新を知らせたい。
同時に更新を知らせるために、CountDownLatchを用いてMultiCastQueueを作成した。

CountDownLatch一回CountDownされたときに待機しているスレッドを解放するように宣言する。更新情報が来るまでawaitを用いてスレッドを待機させる。更新情報が来たときCountDownを行う。すると、スレッドが開放されるので同時に更新情報を参照することができる。
\newpage

\begin{figure}[tb]
\begin{center}
\includegraphics[scale = 0.5]{fig/multicastqueue.eps}
\end{center}
\caption{
クライアントへは並列にデータを送信する。
}
\label{figure:splaying}
\end{figure}

\subsection{TimeOut}
MultiCastQueueを使ってのデータの取得には問題が発生した。
それは、接続してきたクライアントがデータを取得しない状況、例えばサスペンド状態になったときにTopのメモリの中にデータが残り続けるというものである。
メモリに残り続けたデータはやがてメモリオーバーフローを引き起こしてしまうのである。その様子を図2.2に示す。

\begin{figure}[!htbp]
\begin{center}
\includegraphics[scale = 0.5]{fig/TimeOut2.eps}
\end{center}
\caption{
クライアントサスペンド時のTopのメモリの様子。
データが残り続けメモリを圧迫してしまう。
}
\label{figure:splaying}
\end{figure}

そこで、ある一定の時間がたつと代わりにデータを取得してくれるTimeOut用のスレッドを作成した。
TimeOutスレッドはサスペンドしているクライアントの代わりにデータを取得する。

\begin{figure}[!htbp]
\begin{center}
\includegraphics[scale = 0.5]{fig/TimeOut3.eps}
\end{center}
\caption{TimeOutが代わりにデータを取得する}
\label{figure:splaying}
\end{figure}

TimeOutスレッドがクライアントの代わりにデータを取得することで、MulticastQueueの中からデータが削除されTopのメモリを圧迫することがなくなった。

\section{圧縮の問題}
VNCで扱うRFB プロトコルには、使えるエンコーディングのタイプの1つとしてZRLE(Zlib Run-Length Encoding)がある。
ZRLEはZlibで圧縮されたデータとそのデータのバイト数がヘッダーとして付けられ送られてくる。
Zlibはフリーのデータ圧縮及び解凍を行うライブラリである。
可逆圧縮アルゴリズムの圧縮と解凍が行えるjava.util.zip.deflaterとjava.util.zip.inflaterを実装している。

\subsection{java.util.zip.deflaterの実装の問題}
Zlib圧縮は辞書を持っていて、その辞書に登録されているデータを元に解凍が行われる。
しかし、java.util.zip.deflaterは現在持っている辞書を書き出すこと(flush)ができないことが分かった。
辞書を書きだすことができない為、Zlib圧縮されたデータを途中から受け取ってもデータが正しく解凍を行うことができない。
%元々のZlibの規約にはこの辞書をflushする機能があったがJavaには実装されていなかった。

\subsection{ZRLEE}
そこで、TopがZRLEで受け取ったデータをunzipし、データをzipし直して最後にfinish()
をいれることで初めからデータを読んでいなくても解凍を行えるようにした(毎回新しい辞書を使うようにした)。
このエンコードはZRLEEエンコードと定義した。
一度ZRLEEエンコードに変換してしまえば、そのデータをそのまま流すだけで良い。
よって変換はTopが行う一回だけですむ。
ただし、deflater,inflaterでは前回までの通信で得た辞書をクリアしないといけないため、
Topとクライアント側では毎回新しく作る必要がある(クライアント側はinflaterだけ)。
また、ZRLEEはクライアント側が対応していなければならないという問題がある。


\subsubsection{ZRLEとZRLEEのデータ圧縮率の比較}
RAW,ZRLE,ZRLEEのデータ量の比較を行った。                                        
図6は1920 * 1080の画面の全描画にかかるデータ量を測った結果を示した図である。
ZRLEEの方がデータ量が少なくですんでいる。                                          
これは、ZRLE(Zlib)が初めに送られた辞書を用いての解凍が余り有効的に働いていない
場合があるからだと思われる。                                                    
つまりVNCの場合はZRLEEの様に毎回辞書のデータを付加させて送ってもデータ量に差が
でない可能性があることが分かった。                                              


\begin{figure}[!htbp]
\begin{center}
\includegraphics[scale = 0.5]{fig/compare_encoding.eps}
\end{center}
\caption{
RAW,ZRLE,ZRLEEによる1画面(1920*1080)描画にかかるデータ量。
x軸はピクセル数、y軸はバイト数を表している。
}
\label{figure:splaying}
\end{figure}


\newpage


\section{UserInterface}
\subsection{プロキシの検索}
TreeVNCはクライアントが起動した際にBroadcastをしようして、
同じセグメント内にプロキシが起動しているかを調べる。
プロキシはクライアントからBroadcastのリクエストが飛んでくると、
ソケットを張ってクライアントに自分の情報を教える。
\subsection{TreeVNCの使い方}
今回作成したTreeVNCはクライアントが使いやすいように設計を行った。
TreeVNCはまずプロキシを起動させる事が必要である。
プロキシを始動するには-pオプションを指定してやる事で
localhostに対してVNCをかける事ができる。


別のコンピュータの画面共有を行いたい場合は-pオプションを指定してやるか
、第一引数にIpAddress,第に引数にportを指定してやる事で別のコンピュータの
画面共有も行う事ができる。

クライアントは引数なしで実行すると(ダブルクリックで実行できる)
現在つなぐ事のできるプロキシの一覧が表示されるので、選択してつなぐ事ができる。

しかし、Broadcastを使用してプロキシの検索を行っているので、
別セグメントで起動しているプロキシを見つける事ができない。
そこで、TreeVNCを起動する際に-cオプションを付けてやる事で、
アドレス入力欄が表示され、そこに接続したいプロキシのアドレスを
入力する事で、別セグメントのプロキシとも通信をできるようにした。

\section{lionAuthenticate}