サーバーとはずっと待ち続けて、接続してきた相手の要求に応じて仕事をするソフトウェア、またはそのソフトウェアが動いているコンピュータのことを言います。
サーバーのやってくれる仕事をサービスということがあります。サービスを受けるホスト(またはユーザー)をクライアントといいます。
http: で相手をしたのがウェブサーバー、file: で相手をしたのがローカルなファイルシステム(またはファイルサーバー)です。
ネットワークの中で接続するサーバーを指定するのはホスト名あるいはIPアドレスです。しかし,これでは一つのホストが一つのサービスしかできません。
そこでポート番号を使います。ポート番号で管理することで複数の接続を同時に行う事ができます。
銀行の窓口やスーパーマーケットのレジには番号がついていますがそのようなイメージで考えてください。異なるポートに接続する事でちがったサービスを受けられます。たとえばウェブサーバーは80,メール送信は25などです。ポート番号は勝手に使うと通信できなくなりますから,多くの人が使うサービスについては番号が固定されてきました。これをウェルノウンポート(Well known port:よく知られたポート)と呼んでいます。
ポート番号は、0から 65535までの範囲ですが,一般のユーザーのプログラムでは1024よりも大きなものを使うことになっています。他のソフト(サービス)が使っているものと重ならないようにします。
接続してきたら,メッセージを返すだけというサーバーを作ります。このサーバーは 10001 ポートで待ちます。
/** Socketでメッセージを送信するサーバー */ import java.net.*; import java.io.*; import java.util.*; public class Server01 { public static void main( String[] args ) { /* 使用するポート番号 */ int PORT = 10001; /* 応答するメッセージ(3つの文字列の配列) */ /* hoge, vineXX をそれぞれユーザー名、ホスト名に変更 */ String message[] = { "## Welcome to My Server " , "## This is hoge " , "## local host is vineXX " }; try { ServerSocket mysvsoc = new ServerSocket( PORT ); //クライアントが接続してくるのを待ち続ける while( true ) { System.out.println( "Server01 waiting..." ); //接続を待ち続け、接続があると、Socketクラスのオブジェクトを返す Socket mysoc = mysvsoc.accept(); // 接続されたことを画面に表示 String remotehost = mysoc.getInetAddress().getHostName(); Date date = new Date(); System.out.println(date.toString() + ":" + remotehost); // 相手にメッセージを送信 OutputStreamWriter out = new OutputStreamWriter(mysoc.getOutputStream()); BufferedWriter outb = new BufferedWriter(out); for( int i=0; i<message.length; i++ ) { outb.write( message[i] ); outb.newLine(); } outb.close(); out.close(); mysoc.close(); } } catch( IOException e ) { System.err.println("IO Error"); } } }
実行すると次のようになって接続を待ちます
$ java Server01 Server01 waiting...
まだサーバーしかなく接続してくるクライアントはありませんのでいつまでもこのままです。しかし,接続があると次のように時刻と相手のホスト名を表示し,また待機状態に戻ります。
$ java Server01 Server01 waiting... Tue Dec 9 12:50:51 JST 2008:vineXX.st.seiai.ed.jp Server01 waiting...
このサーバーを停止するには ctrl+c (コントロールキーを押しながらc)で止めます。
これはしばらく止めずにおいて,もう一つ端末(コンソール)を起動してクライアントを作りましょう。
端末の起動はもう一度javaを選ぶのが手軽です。アクセサリから端末を起動した場合はカレントディレクトリを移す必要があります。
~$ cd java ~/java$
今度はポート 10001 で接続するクライアントです。サーバーと同じポートを使う事で接続できます。
このクライアントは接続したらサーバーが送ってくるメッセージを画面に表示します。
/** Socketでメッセージを受信するクライアント */ import java.io.*; import java.net.*; public class Client01 { public static void main( String[] args ) { /** 通信に使用するポート番号 */ int PORT = 10001; try { Socket mysoc = new Socket( args[0], PORT ); InputStreamReader in = new InputStreamReader(mysoc.getInputStream()); BufferedReader inb = new BufferedReader(in); String line; while( ( line = inb.readLine() ) != null ){ System.out.println( line ); } inb.close(); in.close(); mysoc.close(); } catch( UnknownHostException e ) { System.err.println( "Host not found" ); } catch( IOException e ) { System.err.println("IO Error"); } } }
実行する時には、
$ java Client01 vineXX
というように引数として自分の使っているコンピュータのホスト名、あるいはIPアドレスを入れます。
実行すると次のようにサーバーからのメッセージを表示します。
$ java Client01 vineXX ## Welcome to My Server ## This is hoge ## local host is vineXX
もちろんこのホスト名にサーバープログラムが動いている他のホストの名前を入れればそちらから応答があります。
vine41 にアクセス
$ java Client01 vine41 ## Welcome to My Server ## This is hoge ## local host is vine41 $
vine39 にアクセス
$ java Client01 vine39 ## Welcome to My Server ## This is foo ## local host is vine39 $
もちろん、相手のサーバーが動いていなければちょっと待たされたあと、エラーになります。
$ java Client01 vine40 Socket Error $
サーバーの方には次のようにアクセス記録が出ます。
$ java Server01 Server01 waiting... Mon Dec 08 21:16:49 JST 2008:vine41.st.seiai.ed.jp waiting... Mon Dec 08 21:20:36 JST 2008:vine42.st.seiai.ed.jp Server01 waiting...
vine41 と vine42 から1回ずつアクセスがあったことを意味します。