年末でJetty(絶対)にできる Android携帯サーバ活用小山博史のJavaを楽しむ(15)(2/4 ページ)

» 2010年12月27日 00時00分 公開
[小山博史,株式会社ガリレオ]

Androidサーバアプリ構築の準備

 携帯サーバ用アプリを開発する前に。Android OSがサポートするAPIを見てみましょう。「java.net.ServerSocket」「java.net.Socket」といったクラスがありますから、基本的にはJava SEでの知識が使えそうです。開発環境を整えて簡単なサンプルを作成してみましょう。

 まず、JDKEclipseAndroid SDKをPCへインストールしました。開発環境をどう用意するかの具体的な方法については、少々古いですが、以下の記事などを参考にしてください。

Windowsから「PuTTY」で接続

 また、ネットワークアプリケーションを開発するには、Telnetクライアントがあった方が何かと便利なので、Windowsで開発をする場合は、「PuTTY」「Terminal Emulator Poderosa」「Tera Term」などから選んで用意しておくといいでしょう。

 今回、WindowsではPuTTYで、RAWデータでやりとりする設定をして動作確認をしました。Mac OS Xではコンソールで普通にtelnetコマンドで接続ができますし、Linuxでは標準で付いている端末をそのまま使えます。

Galaxy Tabエミュレータ用のアドオン

 またAndroid SDKには、Galaxy Tabエミュレータ用のアドオンがあるので、インストールしておくといいでしょう。今回作成してみるネットワークサーバアプリケーションを作るに当たっては、画面サイズは取りあえず気にしなくても構いませんが、設定画面などを作成するときに必要になるはずです。

  1. Android SDK and AVD Managerを起動
  2. [Available packages]を選択
  3. [Third party Add-ons]を指定
  4. 「Samsung Electronics add-ons(innovator.samsungmobile.com)」が表示されるので、その中にある「GALAXY Tab by Samsung Electronics., Android API8, revision 1」をチェック
  5. [Install Selected]をクリック
  6. ライセンスを確認して、[Accept All]をチェックして、インストール

 ただし、GALAXY Tabの仮想マシンを作成すると、かなり高解像度のディスプレイを用意していないと、画面からはみでてしまいます。起動時に[Scale]をチェックすることで、小さい画面にできますから、調整するようにしましょう。

図2 Galaxy Tabエミュレータ 図2 Galaxy Tabエミュレータ

Androidネットワーキングアプリの実装

 Eclipseの[新規プロジェクト]で[Androidプロジェクト]を指定して、次のように各項目を指定してプロジェクトを作成しましょう。

  • [Project name]GalaxyTabSimpleServer
  • [Build Target]GALAXY Tab Addon
  • [Application name]GalaxyTabSimpleServer
  • [Package name]sample.server
  • [reate Activity]GalaxyTabSimpleServer
  • [Min SDK Version]8
図3 GalaxyTabSimpleServerプロジェクト 図3 GalaxyTabSimpleServerプロジェクト

 アプリケーションのサンプルコードは長いので、ポイントだけ示しておきます。接続を待機するためのメインプログラムとして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) {
            }
        }
    }
}
sample/server/GalaxyTabSimpleServer.java

 通信プログラムとしては基本のものなので、それほど難しい内容ではありません。サーバの開始停止はrunnerの値でコントロールしていて、runnerとthreadが一致している間(停止させるときにrunnerにはnullを代入します)、コードの【1】から【2】を繰り返すだけです。文で表すと、以下のようになります。「socket = server.accept();」で下記1.と2.が実行される点に注意してください。

  1. クライアントからの接続を待機
  2. 接続があったらソケット生成
  3. 別スレッドで動くEchoプログラムを生成(ソケットを使用)
  4. threadsへ別スレッドを登録
  5. Echoプログラムの開始

 クライアントとつながったソケットを使って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();
            }
        }
    }
}
sample/server/Echo.java

 ソケットオブジェクトのcloseメソッドを確実に呼ぶために実際のコードはちょっと複雑になっていますが、処理自体は簡単な内容です。readLinesメソッドを呼んでクライアントからの入力を受け取り、replyメソッドを呼んでクライアントへ受け取った文字列をそのまま返すというだけの処理です。

 ただし、「exit」という文字列が来たときだけは、システムが終了するのでreplyメソッドは呼びません。なお、Telnetクライアントから「exit」と入れても終了はしません。通常のtelnetクライアントからくる文字列は改行コードが付くので「exit」という文字列に一致しないからです。

設定ファイル

 インターネット接続が必要なので、AndroidManifest.xmlの要素に追加が必要です。の前に、android.permission.INTERNETの要素を追加します。

<?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.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。