24
|
1 \chapter{画面共有システムTreeVNCの実装}
|
|
2
|
|
3 \section{TightVNCのアップデートへの対応}
|
|
4 TightVNCは現在も開発が続いていて、アップデートされている。このアップデートに対応するために、私が作成しているTreeVNCにも対応させる必要がある。\\
|
|
5 卒業論文後から私は2種類のアップデートを行った。その2種類のアップデートの対応について説明する。\\
|
25
|
6 はじめに行ったアップデートはVersionが1.3.10から2.5.0へ変わるメジャーアップデートと呼ばれる大型アップデートである。\\
|
24
|
7 このアップデートでは、パッケージ構成が追加され、元のソースコードがほとんど残っていない状態であった。このような大型なアップデートに対応するには、新しいTightVNCを元にして、作成したTreeVNCの機能を一つづつ移行していく必要がある。このソースコードのアップデートに加えソースコードの質を高めるためにリファクタリングを行った。
|
|
8 リファクタリングとは、将来の仕様変更に柔軟に対応できるようにソースコードの手直しを行うことである。
|
|
9
|
|
10
|
|
11
|
|
12 \section{UIの実装}
|
25
|
13 \subsection{FramebufferUpdateの概要}
|
24
|
14 RFBプロトコルでは、FramebufferUpdateによって、矩形状の画像データが送信されてくる。\\
|
|
15 FrameBufferUpdateの概要を(表\ref{tb:framebufferupdate},表\ref{tb:framebufferupdate2})に示す。
|
|
16
|
|
17 \begin{table}[htbp]
|
|
18 \caption{FramebufferUpdate}
|
|
19 \label{tb:framebufferupdate}
|
|
20 \begin{center}
|
|
21 \begin{tabular}{|c|c|c|} \hline
|
|
22 バイト数& 型 & 説明 \\ \hline
|
|
23 1 & U8 & message-type \\ \hline
|
|
24 1 & U8 & padding\\ \hline
|
|
25 2 & U16 & number-of-rectangles \\ \hline
|
|
26 \end{tabular}
|
|
27 \end{center}
|
|
28 \end{table}
|
|
29
|
|
30 この後にnumber-of-rectanglesの数だけ矩形のピクセルデータが続く。各矩形は(表\ref{tb:framebufferupdate2})に示す。
|
|
31
|
|
32 \begin{table}[htbp]
|
|
33 \caption{FramebufferUpdate}
|
|
34 \label{tb:framebufferupdate2}
|
|
35 \begin{center}
|
|
36 \begin{tabular}{|c|c|c|} \hline
|
|
37 バイト数& 型 & 説明 \\ \hline
|
|
38 2 & U16 & x-position \\ \hline
|
|
39 2 & U16 & y-position \\ \hline
|
|
40 2 & U16 & width \\ \hline
|
|
41 2 & U16 & height \\ \hline
|
|
42 4 & S32 & encoding-type \\ \hline
|
|
43 \end{tabular}
|
|
44 \end{center}
|
|
45 \end{table}
|
|
46
|
|
47 ここまでがheaderとして送信されるデータである。矩形の画像なのでx-position、y-position、width、heightの4つの値で画像の位置と大きさを決めることができる。\\
|
|
48 headerに続いて、実際の画像データが送信されてくる。\\
|
|
49 画像データはZRLEエンコーディングで送信される。最初の4バイトはデータの大きさを表現して、次にその大きさ分のzlibDataが送信される(表\ref{tb:ZRLE})。
|
|
50
|
|
51 \begin{table}[htbp]
|
|
52 \caption{ZRLEデータ}
|
|
53 \label{tb:ZRLE}
|
|
54 \begin{center}
|
|
55 \begin{tabular}{|c|c|c|} \hline
|
|
56 バイト数& 型 & 説明 \\ \hline
|
|
57 4 & U32 & length \\ \hline
|
|
58 length & U8 array & zlibData \\ \hline
|
|
59 \end{tabular}
|
|
60 \end{center}
|
|
61 \end{table}
|
|
62
|
|
63 送られてきたzlibDataは展開されると左から右、上から下へ並んだ、64*64ピクセルのタイル群画像データとなる。
|
|
64
|
|
65 ここで、画像データがどのように送られてくるのかを調べてみたところ、2つディスプレイがあるとすると、両ディスプレイにまたがった画像更新が来ることがないことがわかった。\\
|
|
66 図\ref{fig:rawdata}の黒い部分が画像データだとすると、図\ref{fig:rawdata}のようなFramebufferUpdateは送られてくることはない。
|
|
67
|
|
68 \begin{figure}[!htbp]
|
|
69 \begin{center}
|
|
70 \includegraphics[width=110mm]{./images/sendscreenimage.pdf}
|
|
71 \end{center}
|
|
72 \caption{画面更新時に来る可能性のないUpdateRectangle}
|
|
73 \label{fig:sendscreenimage}
|
|
74 \end{figure}
|
25
|
75 \subsection{マルチディスプレイへの対応}
|
|
76 VNCでは画面の情報を矩形型にして送信する。もし複数のディスプレイが存在する場合すべてのディスプレイの情報が送られてくる。しかし、発表などに使用するディスプレイは一つである場合が多い。\\
|
|
77 必要な画像が一つのディスプレイなのに、すべてのディスプレイのデータを送ると無駄なデータが発生する。そこで、ディスプレイを指定して、その画像だけ送信する機能を追加することで、無駄なデータ送信を省くことができる。
|
|
78
|
|
79
|
24
|
80
|
|
81 以上のことを踏まえ、FramebufferUpdateで送信されてきたheaderを確認し、x-positionを確認することで、どの画面の画像データを送信するかを選択することができる。\\
|
|
82 例えば、図\ref{fig:rawdata}では、左側の画面を送信したいときは、x-positionが1920より小さい場合送信し、右側を送信したい場合は1920以上のデータを送信するようにフィルタリングすることで実現できる。
|
|
83
|
|
84 \newpage
|
|
85
|
|
86 \subsection{表示画面の切り替え}
|
|
87 ゼミなど発表者が多数いる状況でVNCを使用すると、発表者が切り替わるごとにサーバを立ち上げなおさなければならない。\\
|
|
88 画面の切替手順を図\ref{fig:changevncserver}に示す。
|
|
89
|
|
90 \begin{figure}[!htbp]
|
|
91 \begin{center}
|
|
92 \includegraphics[width=150mm]{./images/changevncserver.pdf}
|
|
93 \end{center}
|
|
94 \caption{画面切り替えの流れ}
|
|
95 \label{fig:changevncserver}
|
|
96 \end{figure}
|
|
97
|
25
|
98 初めに、Root Nodeに対して画面を切り替える命令(1:changeVNCServer("10.3"))を出す。命令を受け取ったRoot Nodeは引数で受けっとた
|
|
99 IPのコンピュータに対して、接続要求を出す(2:requestVNC())。要求を受け取ったコンピュータはが認証を承諾するとRoot Nodeに対して、接続要求を承諾したことを通知する(3:acceptConnection())。Root Nodeは元から通信していたネットワーク接続を閉じる命令を出す(4:CloseConnection())。最後に繋がっているNodeに新しい画面に切り替わったことを通知する(5:newServer())。
|
24
|
100
|
|
101 newServer()の内部処理ををListing\ref{src:changescreen}に示す。これは、Root Nodeが子供に対して、画面の切り替えが起こったことを知らせるソースコードである。\\
|
|
102 clientListは、現在接続されているクライアント情報が入っている。クライアントにそれぞれTCP接続を行い、サーバが変わったので接続し直させる命令を送信する。
|
|
103
|
|
104 \begin{lstlisting}[language=java,frame=lrbt,label=src:changescreen,caption=画面が切り替わったことを知らせるプログラム,numbers=left]
|
|
105 for (String client : clientList) {
|
|
106 Socket echoSocket = new Socket(client, 10001);
|
|
107 DataOutputStream os = new DataOutputStream(echoSocket.getOutputStream());
|
|
108 os.writeBytes("reconnection\n");
|
|
109 os.close();
|
|
110 }
|
|
111 \end{lstlisting}
|
|
112
|
|
113
|
|
114 \section{Authentication}
|
|
115 Root Nodeがサーバに対してVNC接続を行う際、ハンドシェイクが必要となる。
|
25
|
116 ハンドシェイクの手順として、始めにRoot Nodeがサーバに接続を行うと、
|
24
|
117 サーバがサポートする最新のプロトコルバージョンが送られてくる。
|
|
118 Root Nodeはサーバから送られてきたプロトコルバージョン以下の使用できるバージョンを
|
|
119 サーバに対し送る。現時点で公開されているプロトコルバージョンは3.3、3.7、3.8だけである。
|
|
120 今回TreeVNCは3.855というバージョンを用意して3.855が来るとTreeVNCを使用するようにした。
|
|
121
|
|
122 プロトコルバージョンが決定すると、サーバ及びNodeは、
|
|
123 その接続で使用されるセキュリティに合意しなければならない。
|
|
124 バージョン3.7以降ではサーバは自身のサポートするセキュリティタイプの一覧を提示する。
|
|
125 Nodeのサポートする有効なセキュリティタイプを少なくとも一つサーバが提示した場合、Nodeはその接続上で使用されるセキュリティタイプを表す単一バイトを送り返す。
|
|
126
|
|
127 登録されているセキュリティタイプの一例として(表 \ref{tb:authtype})のようなものがある。
|
|
128
|
|
129 \begin{table}[htbp]
|
|
130 \caption{AuthType}
|
|
131 \label{tb:authtype}
|
|
132 \begin{center}
|
|
133 \begin{tabular} {|l|l|}
|
|
134 \hline
|
|
135 {\bf 値}&名称\\
|
|
136 \hline
|
|
137 {\bf 0}&Invalid\\
|
|
138 \hline
|
|
139 {\bf 2}&None\\
|
|
140 \hline
|
|
141 {\bf 5}&RA2\\
|
|
142 \hline
|
|
143 {\bf 18}&TLS\\
|
|
144 \hline
|
|
145 {\bf 21}&MD5 ハッシュ認証\\
|
|
146 \hline
|
|
147 \end{tabular}
|
|
148 \end{center}
|
|
149 \end{table}
|
|
150
|
|
151 MAC OS X SnowLeopardで起動しているVNCサーバに接続するときには
|
|
152 MAC専用の認証の値35がありこれでパスワード認証を行うことができていた。
|
|
153
|
|
154 しかしMAC OS X Lionでパスワード認証を行おうとすると、
|
|
155 MAC OS X Lionにしてパスワード認証ができなくなったので、
|
|
156 別の認証方法で認証を行うことにした。
|
|
157
|
|
158 調べてみるとMAC OS Xが返してくる認証番号は[30, 31, 32, 2, 35]がある。
|
|
159 32はサーバに対して画面要求の認証を求めるタイプの認証であることがわかった。
|
|
160 この認証を用いるとサーバに対してRoot Nodeが接続する際にサーバ側に確認画面が出るようになる。
|
|
161 サーバ側がこれを容認すると認証が成立する。
|
|
162
|
|
163 \newpage
|
|
164
|
|
165
|
|
166
|
|
167 \section{接続先自動検索システムの実装}
|
|
168 Listing\ref{src:gethost}はBroadcastを使用して、データを送信するプログラムである。
|
25
|
169 起動しているRoot NodeはBroadcastパケットが流れてくるのを待っている(Listing\ref{src:gethost})。
|
|
170 Javaでは、Broadcastパケットを作成す際は、java.net.DatagramPacketを使用する。
|
24
|
171 \begin{lstlisting}[language=java,frame=lrbt,label=src:gethost,caption=Broadcastを用いてサーバを探すプログラム,numbers=left]
|
|
172 public GetHostClient(String _str) {
|
|
173 str = _str;
|
|
174 }
|
|
175
|
|
176 public void sendData() {
|
|
177 buf = str.getBytes();
|
|
178 DatagramPacket sendPacket = new DatagramPacket(buf, str.length(), mAddr, PORT);
|
|
179 try {
|
|
180 soc.send(sendPacket);
|
|
181 } catch (IOException e) {
|
|
182 e.printStackTrace();
|
|
183 }
|
|
184 }
|
|
185 \end{lstlisting}
|
25
|
186
|
|
187 Listing\ref{src:gethost}のif文の中でstrと受け取った値(recvPacket.getData())を比較しているが、このstrを任意に決めることで、strの情報を知らない人には一覧情報が提供されなくなる。
|
|
188 一覧情報が提供されない場合はIPアドレスを直接指定しなければ接続することができないので、IPアドレスとstrを知らない人は接続することができないので、プライベートな画面共有を行うこともできるように実装している。
|
|
189 Broadcast Packetを受け取ると、受け取ったIPアドレスに対し、TCPコネクションを張り、現在起動しているVNC Serverの一覧を送る(replayBroadcast())。
|
24
|
190 \begin{lstlisting}[language=java,frame=lrbt,label=src:getbroadcast,caption=Broadcastを受け取るプログラム,numbers=left]
|
|
191 byte[] buf = new byte[BufSize];
|
|
192 byte[] resorve = new byte[BufSize];
|
|
193 try {
|
|
194 InetAddress mAddr = InetAddress.getByName(McastAddr);
|
|
195 MulticastSocket soc = new MulticastSocket(Port);
|
|
196 DatagramPacket recvPacket = new DatagramPacket(buf, BufSize);
|
|
197 soc.joinGroup(mAddr);
|
|
198 while (!stopFlag) {
|
|
199 soc.receive(recvPacket);
|
|
200 address = getAddress(recvPacket.getSocketAddress());
|
|
201 inputStream = new ByteArrayInputStream(recvPacket.getData());
|
|
202 inputStream.read(resorve);
|
|
203 if(str.equals(castString(resorve)))
|
25
|
204 replyBroadcast();
|
24
|
205 if(stopFlag) break;
|
|
206 } catch (IOException e) {
|
|
207 e.printStackTrace();
|
|
208 }
|
|
209 }
|
|
210 \end{lstlisting}
|
|
211
|
|
212
|
|
213 Listing\ref{src:gethost}は、Root Nodeから受け取ったVNCServer一覧を表示する部分である。ここで使用されているtextは、javaのGUIコンポーネントであるJFrameを継承したクラスのインスタンスである。
|
|
214 \begin{lstlisting}[language=java,frame=lrbt,label=src:getaddr,caption=起動サーバ一覧を表示するプログラム,numbers=left]
|
|
215 Socket socket = server.accept();
|
|
216 is = new BufferedReader(new InputStreamReader(
|
|
217 socket.getInputStream()));
|
|
218 proxyAddr = is.readLine();
|
|
219 if(proxyAddr!=null)
|
|
220 text.checkBox(proxyAddr);
|
|
221 text.setButton();
|
|
222 text.visible();
|
|
223 \end{lstlisting}
|
|
224
|
|
225
|
|
226
|
|
227
|
|
228 %各64*64のタイル群の先頭には、1byteのsubencordingタイプが設定されている。
|