携帯サーバ用アプリを開発する前に。Android OSがサポートするAPIを見てみましょう。「java.net.ServerSocket」「java.net.Socket」といったクラスがありますから、基本的にはJava SEでの知識が使えそうです。開発環境を整えて簡単なサンプルを作成してみましょう。
まず、JDKやEclipse、Android SDKをPCへインストールしました。開発環境をどう用意するかの具体的な方法については、少々古いですが、以下の記事などを参考にしてください。
また、ネットワークアプリケーションを開発するには、Telnetクライアントがあった方が何かと便利なので、Windowsで開発をする場合は、「PuTTY」「Terminal Emulator Poderosa」「Tera Term」などから選んで用意しておくといいでしょう。
今回、WindowsではPuTTYで、RAWデータでやりとりする設定をして動作確認をしました。Mac OS Xではコンソールで普通にtelnetコマンドで接続ができますし、Linuxでは標準で付いている端末をそのまま使えます。
またAndroid SDKには、Galaxy Tabエミュレータ用のアドオンがあるので、インストールしておくといいでしょう。今回作成してみるネットワークサーバアプリケーションを作るに当たっては、画面サイズは取りあえず気にしなくても構いませんが、設定画面などを作成するときに必要になるはずです。
ただし、GALAXY Tabの仮想マシンを作成すると、かなり高解像度のディスプレイを用意していないと、画面からはみでてしまいます。起動時に[Scale]をチェックすることで、小さい画面にできますから、調整するようにしましょう。
Eclipseの[新規プロジェクト]で[Androidプロジェクト]を指定して、次のように各項目を指定してプロジェクトを作成しましょう。
アプリケーションのサンプルコードは長いので、ポイントだけ示しておきます。接続を待機するためのメインプログラムとしてsample.server.GalaxyTabSimpleServerクラスを用意し、実際のサービスを提供するプログラムとしてsample.server.Echoクラスを用意してみました。
実際のコードでは、onStop()メソッドがあったり、ログの出力などもしていますが、ここでは省略してあります。
public class GalaxyTabSimpleServer extends Activity implements Runnable { ServerSocket server; Socket socket; int port = 8080; volatile Thread runner = null; private static List<Thread> threads = new ArrayList<Thread>(); @Override protected void onStart() { super.onStart(); if (runner == null) { runner = new Thread(this); runner.start(); } Toast.makeText(this, "onStart()", Toast.LENGTH_SHORT).show(); } public void run() { Thread thread = Thread.currentThread(); try { server = new ServerSocket(port); while (thread == runner) { // 【1】 try { socket = server.accept(); Thread appThread = new Thread(new Echo(socket)); threads.add(appThread); appThread.start(); } catch (IOException e) { } } // 【2】 } catch (IOException e) { } finally { try { server.close(); } catch (IOException e) { } } } }
通信プログラムとしては基本のものなので、それほど難しい内容ではありません。サーバの開始停止はrunnerの値でコントロールしていて、runnerとthreadが一致している間(停止させるときにrunnerにはnullを代入します)、コードの【1】から【2】を繰り返すだけです。文で表すと、以下のようになります。「socket = server.accept();」で下記1.と2.が実行される点に注意してください。
クライアントとつながったソケットを使ってEchoプログラムは別スレッドで動作します。Echoプログラムのスレッドはサーバ側でthreadsに入れて管理します。実際のコードでは終了したスレッドをtheadsから取り除くといった程度の簡単な処理が入れてありますが、ここでは省略しています。
Echoプログラムは次のようになります。
public class Echo implements Runnable { private Socket socket; public Echo(Socket socket) { super(); this.socket = socket; } public void run() { // readLines()メソッドを呼ぶ } private void readLines() throws IOException { // 略 try { in = socket.getInputStream(); size = in.read(w); if (size <= 0) { throw new IOException(); } message = new String(w, 0, size, "UTF8"); if (!message.equals("exit")) { reply(message); } } catch (IOException e) { } finally { if (in != null) { in.close(); } } } public void reply(String message) throws IOException { OutputStream out = null; String s = message; try { out = socket.getOutputStream(); byte[] w = s.getBytes("UTF8"); out.write(w); out.flush(); } catch (IOException e) { } finally { if (out != null) { out.close(); } } } }
ソケットオブジェクトのcloseメソッドを確実に呼ぶために実際のコードはちょっと複雑になっていますが、処理自体は簡単な内容です。readLinesメソッドを呼んでクライアントからの入力を受け取り、replyメソッドを呼んでクライアントへ受け取った文字列をそのまま返すというだけの処理です。
ただし、「exit」という文字列が来たときだけは、システムが終了するのでreplyメソッドは呼びません。なお、Telnetクライアントから「exit」と入れても終了はしません。通常のtelnetクライアントからくる文字列は改行コードが付くので「exit」という文字列に一致しないからです。
インターネット接続が必要なので、AndroidManifest.xmlの
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" // 略 <uses-permission android:name="android.permission.INTERNET"></uses-permission> </manifest>
次ページで、動作確認をしてみます。
Copyright © ITmedia, Inc. All Rights Reserved.