ウェブアプリケーション,インジェクション,コマンドインジェクション

Androidアプリ開発 ネットワークプログラミング

ソケットサーバを作る

Creating a Socket Server

ソケットはアプリケーションの終点で、ネットワークを解する
2方向のコミュニケーションに加わっています。
ソケットはIPアドレスとポート番号から出来ています。
ソケットを使うと、アプリケーションはネットワークを介して
効率的にデータを送信することができます。
ここでは、入ってくるコネクションを注視するソケットサーバを
作る方法を示します。
ソケットクライアントを作るでは、
サーバに接続するソケットクライアントを開発する方法を示します。
ソケットサーバを作るためには、ます以下のように4つのオブジェクトを
宣言します。

static String SERVER_IP;
static final int SERVER_PORT = 5000;
Handler handler = new Handler();
ServerSocket serverSocket;

最初のオブジェクトはデバイスのIPアドレスを保持し
ソケットサーバのように動作します。
2番目のオブジェクトはサーバと繋がっているポート番号を保持します。
理論上なら、0から65535のいずれかのポート番号を使えますが、
実際のポート番号は0から1023で、大抵は権限のあるサーバで
処理させていくために受信されます。
そのため、ポート番号は1024から65535になる可能性があり、
開発者が選択したポート番号が同じで、同じポート番号を使っている
他のアプリケーションが同じデバイス上で走ることでポート番号が
衝突しない限りそのポート番号を使います。
Handlerオブジェクトは開発するユーザインターフェースに使われます。
大抵は、ユーザインターフェースや
更新の必要のあるユーザインターフェース以外の分離したスレッド上で
今現在実行していたら、このHandlerが必要になります。
これは重要で、ネットワーク操作はユーザインターフェースから
直接呼び出されることが許されていないからです。
このため、ネットワークスレッドからユーザインターフェースに
反映する必要のあるすべての更新にHandlerオブジェクトを
使用させることが必要になります。
ServerSocketはスレッドで、入ってくるソケット接続用に
注視した後定義されます。
単純化するために、デバイスのIPv4アドレスを使って
ソケットサーバの実行をしていきます。
以下のgetLoclaIpv4Address()メソッドは、このメソッドが走っている
AndroidデバイスのIPv4アドレスを返します。

//---get the local IPv4 address---
public String getLocalIpv4Address(){
  try{
   for (Enumeration<NetworkInterface> networkInterfaceEnum =
   NetworkInterface.getNetworkInterfaces();
   networkInterfaceEnum.hasMoreElement();){
   NetworkInterface networkInterface = networkInterfaceEnum
      .nextElement();
    for (Enumeration<InetAddress> ipAddressEnum = networkInterface
       .getInetAddresses(); ipAddressEnum.hasMoreElements();){
     InetAddress inetAddress = (InetAddress) ipAddressEnum.nextElement();
     //---check that it is not a loopback address and it is IPv4---
     if(!inetAddress.isLoopbackAddress() &&
        InetAddressUtils.isIPv4Address(inetAddress.getHostAddress())){
        return inetAddress.getHostAddress();
     }
    }
   }
  }catch(SocketException ex){
   Log.d("IPAddress", ex.toString());
  }
  return null;
}

ソケットサーバを実行するためには、以下のように
Runnableインターフェースを実行するServerThreadクラスを作ります。

public class ServerThread implements Runnable{
  public void run(){
   try{
    if(SERVER_IP != null){
     @Override
     public void run(){
      textView1.setText(textView1.getText()
       + "Server listening on IP:" + SERVER_IP + "\n");
     }
    });

    while (true){
     //---wait for incoming client---
     Socket client = serverSocket.accept();

     //---the above code is a blocking call;
     //i.e. it will block until a client connects---

     //---client has connected---
     handler.post(new Runnable(){
      @Override
      public void run(){
       textView1.setText(textView1.getText() + "Connected to client."
            + "\n");
      }
     });

     try{
      //---get an InputStream object to read from the socket---
      BufferedReader br = new BufferedReader(
         new InputStreamReader(client.getInputStream()));

      OutputStream outputStream = client.getOutputStream();

      //---read all incoming data terminated with a \n char---
      String line = null;
      while((line = br.readLine()) != null){
        final String strReceived = line;

       //---send whatever you received back to the client---
       String s = line + "\n";
       outputStream.write(s.getBytes());

       handler.post(new Runnable(){
        @Override
        public void run(){
         textView1.setText(textView.getText() + strReceived + "\n");
        }
       });
     }

     //---client has disconnected fro the server---
     handler.post(new Runnable(){
      @Override
      public void run(){
       textView1.setText(textView1.getText() + "Client disconnected."
       + "\n");
      }
     });

     }catch (Exception e){
      final String error = e.getLocalizedMessage();
      handler.post(new Runnable(){
       @Override
       public voic run(){
        TextView1.setText(textView1.getText() + error);
       }
      });
     }
    }
   }else{
    handler.post(new Runnable(){
     @Override
     public void run(){
       textView1.setText(textView1.getText() +
        "No internet connection on device" + "\n");
     }
    });
   }
  }catch(Exception e){
    final String error = e.getLocalizedMessage();
    handler post(new Runnable(){
     @Override
     public void run(){
      textView1.setText(textView1.getText() + error + "\n");
     }
    });
   }
   handler.post(new Runnable(){
    @Override
    public void run(){
     textView1.setText(textView1.getText() + "\n" +
       "Server exited" + "\n");
    }
   });
  }
}

ServerThreadクラスは以下のような事をします。
●ServerThreadクラスはServerSocketクラスを使って
サーバソケットを作り、監視すべきポート番号をこれに渡します。
●ServerThreadクラスはソケットオブジェクトのaccept()メソッドを
使って入ってくるソケット接続を監視します。
これはブロッキングコールで、クライアントが接続された後でのみ
実行が続けられます。
●クライアントが接続されたら、クライアントから
InputStreamオブジェクトを得て、結果、
クライアントから読むことができます。クライアントから読むためには、
BufferedReaderオブジェクトを使います。
クライアントからOutputStreamオブジェクトも取得し、クライアントに
出力を戻すことができます。上のコードの例では、
OutputStreamオブジェクトから受信したものは何でも、
クライアントに送り戻しています。
●サーバはクライアントがサーバにデータを送信するのを待ちます。
そのデータは改行("\n")文字で終わる必要があります。
これはクライアントが接続を断つまで無制限に動きます。
●ユーザインターフェースを更新するためにHandlerオブジェクトを
使います。
ソケットサーバをスタートさせるためには、
アクティビティのonStart()メソッドを使うことができます。
ただ、アクティビティが前面に来たときにですが。

@Override
protected void onStart(){
  super.onStart();
  //---get the IP address of itself---
  SERVER_IP = getLocalIpv4Address();

  //---start the server---
  Thread serverThread = new Thread(new ServerThread());
  serverThread.start();
}

アクティビティがバックグラウンドに移った時には、
アクティビティのonStop()メソッドにあるソケットサーバを閉じます。

@Override
protected void onStop(){
  super.onStop();
  try{
   serverSocket.close();
  }catch(IOException e){
   e.printStackTrace();
  }
}

ソケット接続にも関わらずですが、AndroidManifest.xmlファイルに
INTERNETパーミッションが必要になります。

<uses-permission android:name="android.permission.INTERNET" />

実際のAndroidデバイスでこのアプリケーションを展開したときには、
IPアドレスが表示されるはずです。


ちょっと注釈

AVD、Androidエミュレータでこのアプリケーションを展開した場合、
10.0.2.15の固定されたIPアドレスが表示されます。
さらにいくつかのAndroidエミュレータで走らせると、
それぞれこの固定されたIPアドレスになると思います。
そのため実際のAndroidデバイスのサーバでテストすることを
おすすめします。
ソケットクライアントを作る
このサーバに接続するソケットクライアントを構築します。

ホーム
便利堂ロゴ
inserted by FC2 system