小さなHTTPサーバーNanoHTTPDを使う&改造する
今年の4月ごろからAndroid開発を始めたのです。
だからJavaもやってるのです。
そして、突然新しいアプリのネタを思いついてしまったのです。
というわけで、今日は、Javaソースコード1ファイルだけの小さなHTTPサーバー、NanoHTTPDというものを見つけたので動かして、それを改造するのですよー!
NanoHTTPDは http://elonen.iki.fi/code/nanohttpd/ ここからダウンロードできるのですよ。
改造後のNanoHTTPDと自分で書いたコードはgistにアップロードしてあります。
https://gist.github.com/3436665
そのまま動かしてみる
まずNanoHTTPDのソースコードをダウンロードし、それをjavacでコンパイルします。
普通に
javac NanoHTTPD.java
でコンパイルして
java NanoHTTPD -p 44444
と起動します。-pの後に数字を入れてポートを指定するとサーバーを起動でき、起動したディレクトリにあるファイルにアクセスできます。
組み込んでみる
ここは後付けで書いたため短く薄いです。
NanoHTTPDのサンプルコードにHelloServer.javaというのがあったのでそれ参考です。
ただし、superの引数が違っていたと思います。バージョンの違いでしょうか。
NanoHTTPDを継承したクラスを作り、コンストラクタでは適当に初期化します。
superの引数はポート番号とFileですが、ファイルを使わないのならnullで大丈夫です。
実際の処理はserveメソッドです。ここでは、最初の引数がファイルパスなのでこれで分岐して処理します。
改造しちゃう
ここで思いっきり改造します。
まず、コンパイルする時に警告が出ないようにしました。
修正箇所は、HashtableやVectorをVector
また、「リアルタイムでクライアントにデータを通知したい!」と思ったのでchunkedなレスポンスを返せるようにしました。
chunkedについては http://d.hatena.ne.jp/kiririmode/20100606/p1 ここを参考にしています。
ただし、ここで大きなミスにはまってしまいました。
NanoHTTPDではデータを読み込んでクライアントに送るところでInputStreamを使っているのですが、ほとんどそのままやってみた場合、
InputStreamをreadしているところで、InputStreamにデータを送り込む側のPipedOutputStreamをcloseしても止まりませんでした。無限ループです。
実は大きな落とし穴がありました。
InputStreamのreadメソッドは、3つの引数を与えた場合は読み込んだバイト数を返しますが、
ストリームが終わっている場合は-1を返します。
しかし3つめの引数(たぶん読み込むバイト数か終わりの位置)が0の場合、ストリームが終わっていても-1ではなく0を返すようです。
それが、一旦残りが無くなっても本当に終わる、つまり-1を返すまで終了しないという改造部分に引っかかり無限ループしていたのでした。
これで、serveの戻り値でResponseを作るところでPipedInputStreamを渡せば、少しずつデータが送られてくるプログラムが作れます。