このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
RFB は、双方向に通信ができる環境で利用できる。
このような環境を Java で表すとすれば、
InputStream と OutputStream のペアで表現される事になる。
さて、VNCServer がクライアントとの接続を確立した後は、
クライアントとの通信用のソケットを使って処理するが、
RFB の世界にソケットを持ち込みたくはない。
そこで、とりあえず VNCSession というクラスを作り、
クライアントとの通信用のソケットから、
InputStream と OutputStream を取り出すコードを書こう。
========== VNCSession.java ==========
package jp.loafer.rfbdemo;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* VNC クライアントとの通信
* @author kes
*/
public class VNCSession implements Runnable {
/**
* {@link VNCSession} のインスタンスを作成。
* @param client 接続してきたクライアントソケット。
*/
public VNCSession(Socket client) {
socket = client;
}
/**
* @see java.lang.Runnable#run()
*/
public void run() {
try {
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
// メイン処理が来る予定
} catch (Exception e) {
e.printStackTrace(System.err);
} finally {
try {
socket.close();
} catch (IOException e) {
// 例外無視
}
}
}
private Socket socket;
}
========== end of VNCSession.java ==========
これも大したことをしていないクラスだ。
コンストラクタで Socket を受け取り、
run ではそれを使って通信を行う。
Runnable#run ではソケット固有の処理をしている。
getInputStream, getOutputStream を呼び出せば、
通信に使える汎用の入出力ストリームが得られる。
また、例外の捕捉とソケットを閉じる処理を入れておけば、
ソケットに依存する部分はクラスから分離できる。
後は、上記で得られた入出力ストリームを元にして、
RFB の処理を行うクラスを呼べばよい訳だ。
上記では「メイン処理が来る予定」とコメントにしている。
では、これを使うように VNCServer#run を修正しよう。
========== VNCServer#run ==========
/**
* @see java.lang.Runnable#run()
*/
public void run() {
while (!socket.isClosed()) {
try {
Socket client = socket.accept();
VNCSession session = new VNCSession(client);
new Thread(session, "VNCSession").start();
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
}
========== end of VNCServer#run ==========
クライアントとのセッションを別スレッドで走らせる。
例によって、スレッドは放りっぱなしである。
ところで、このような書き方は、
Java に慣れた方には違和感があるかもしれない。
ハンドラを分離し、インタフェースを定め、
洗練された設計をすることもできるからだ。
しかしながら、今回は実装を目的としているため、
美しいとか再利用性とかは考えずに、
直接的なコーディングで進めようと思っている。