ソケットサーバを作る
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デバイスのサーバでテストすることを
おすすめします。
ソケットクライアントを作るで
このサーバに接続するソケットクライアントを構築します。
|
【用語解説】
XML
HTMLと同じような言語ですが、
すべての型の複雑なデータ構造を
送信するための設計ができる
ファイル型式。
オブジェクト
ある手続きを持った
データアイテムで、
他の手続きと関連づけされるもの
metaタグ
ウェブページに与える
情報の宣言につかわれ
検索エンジン・ウェブアプリ
などにウェブページの内容を
伝える役目をする。
metaタグの内容は
ページ内に表示されない。
コンストラクタ
オブジェクト指向
プログラミングで使われ
新しいオブジェクトが
作られ時に呼び出される
メソッドのこと。
クラス
オブジェクト指向
プログラミングでの
オブジェクトの型
オブジェクト指向プログラミング
プログラミングの
方式のことで、
プログラマはデータ型を
定義できるだけでなく
自動的にデータ型と
メソッドを関連付け
できる
アクティビティ
Androidにおける
アクティビティは
Androidアプリの画面に
相当するもの
ボタンやウェブページ
など表示されている
すべてのもののこと。
view
Androidのアプリを開発する
上で使う部品のことで、
トリガボタン・イメージボタン
チェックボックスなどのこと。
UI
ユーザインターフェースのこと。
Bind(バインド)
シンボルとデータを
関連させるため
または、データの一片と
他のものを関連させること。
以下は例。
・変数に値を入れる。
(変数の初期化)
・特定のEthernetポートと
ネットワークプロトコルを
関連付けする。
・Javaの変数のセット上に
XML文書を配置すること。
または、ほかの
プログラミング言語でも。
|