システムプログラム(第7週): echoサーバ(Java版)

                                       筑波大学 システム情報工学研究科 
                                       コンピュータサイエンス専攻, 電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~syspro/2011/2011-06-08/echo-server-java.html
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~syspro/2011/
http://www.coins.tsukuba.ac.jp/~yas/

echoサーバ(Java版)

main()

   1:	/*
   2:	        EchoServerSingle.java -- 文字列を送受信するサーバ(TCP/IP, Java版, スレッドなし)
   3:	        ~yas/syspro/ipc/EchoServerSingle.java
   4:	        Created on 2004/05/09 20:00:24
   5:	*/
   6:	
   7:	import java.net.*;
   8:	import java.io.*;
   9:	
  10:	class EchoServerSingle
  11:	{
  12:	    public static void main(String argv[]) throws IOException {
  13:	        if( argv.length != 1 )
  14:	        {
  15:	            stderr.printf("Usage: %% java EchoServerSingle port\n");
  16:	            System.exit( -1 );
  17:	        }
  18:	        int portno = Integer.parseInt( argv[0] );
  19:	        echo_server_single( portno );
  20:	    }
  21:	
引数として、ポート番号を取る。

echo_server_single()

  22:	    public static void echo_server_single( int portno ) throws IOException
  23:	    {
  24:	        ServerSocket acc = new ServerSocket( portno );
  25:	        print_my_host_port( portno );
  26:	        while( true )
  27:	        {
  28:	            Socket com = acc.accept();
  29:	            tcp_peeraddr_print( com );
  30:	            EchoServerWorker esw = new EchoServerWorker(com);
  31:	            esw.run();
  32:	        }
  33:	    }

echo_server_single() は、 引数で与えられたポート番号を使って接続要求受付用ポー トを作成し、それに対応した ServerSocket のオブジェクトを返す。このオブ ジェクトは、Socket のオブジェクトとは異なり、そまままでは通信に用いる ことはできない。

print_my_host_port() は、telnet で接続する時のヒントを表示する。

サーバのプログラムの特徴は、内部に無限ループを持っていることである。 サーバは、普通の状態では、終了しない。

accept() は、接続要求を待つメソッドである。クライアントから接続が来る まで、システムコールを実行したまま止まっているように見える。接続要求が 届くと、TCP/IP通信路の開設され、通信用ポートに対応したSocket クラスの オブジェクトが返される。このオブジェクトは、クライアント側と同様に getInputStream() や getOutputStream() により入出力可能なストリームを作 り出すことができる。

tcp_peeraddr_print() は、通信相手の IP アドレスとポート番号を表示する関数である。

以後の仕事は、EchoServerWorker というクラスのオブジェクトを作成して行 わせている。コンストラクタでは、Socket クラスのオブジェクトを渡してい だけであり、実際の処理は何も行われない。実際の処理は、run() メソッドで 行われる。

print_my_host_port()

print_my_host_port() は、同じ同名のCの関数と同じ働きをする。
  34:	    public static void print_my_host_port( int portno ) throws UnknownHostException
  35:	    {
  36:	        InetAddress ia = java.net.InetAddress.getLocalHost();
  37:	        String hostname = ia.getHostName();
  38:	        stdout.printf("run telnet %s %d\n",hostname, portno );
  39:	    }

tcp_peeraddr_print()

tcp_peeraddr_print() は、同じ同名のCの関数と同じ働きをする。
  40:	    public static void tcp_peeraddr_print( Socket com )
  41:	    {
  42:	        InetSocketAddress isa = (InetSocketAddress)com.getRemoteSocketAddress();
  43:	        InetAddress ia = isa.getAddress();
  44:	        String peerhostaddr = ia.getHostAddress();
  45:	        int peerportno = isa.getPort();
  46:	        stdout.printf("connection (hash== %s) from %s:%d\n", com.hashCode(),
  47:	                      peerhostaddr, peerportno );
  48:	    }

stdoutとstderr

以下の変数 stdoutとstderr は、C 言語のプログラムに似せるために 定義している。
  49:	    static java.io.BufferedReader stdin = 
  50:	        new java.io.BufferedReader( new java.io.InputStreamReader(System.in) );
  51:	    static java.io.PrintStream stdout = System.out;
  52:	    static java.io.PrintStream stderr = System.err;     
  53:	}

EchoServerWorker

   1:	/*
   2:	        EchoServerWorker.java -- 文字列を送受信するサーバ/ワーカ(TCP/IP, Java版)
   3:	        ~yas/syspro/ipc/EchoServerWorker.java
   4:	*/
   5:	
   6:	import java.net.*;
   7:	import java.io.*;
   8:	
   9:	public class EchoServerWorker implements Runnable
  10:	{
  11:	    Socket com ;
  12:	    EchoServerWorker( Socket com )
  13:	    {
  14:	        this.com = com ;
  15:	    }
  16:	    public void run()
  17:	    {
  18:	        try
  19:	        {
  20:	            BufferedReader in = new BufferedReader(
  21:	                new InputStreamReader( com.getInputStream() ));
  22:	            PrintStream out = new PrintStream( com.getOutputStream() );
  23:	            String line;
  24:	            while( (line = in.readLine())!= null )
  25:	            {
  26:	                stdout.printf("received (hash==%s) %d characters, [%s]\n",
  27:	                              com.hashCode(), line.length(),line );
  28:	                out.printf("%s\n", line );
  29:	            }
  30:	            stdout.printf("connection (hash==%s) closed.\n", com.hashCode());
  31:	            in.close();
  32:	            out.close();
  33:	            com.close();
  34:	        }
  35:	        catch( IOException e )
  36:	        {
  37:	            stderr.println( e );
  38:	        }
  39:	    }
  40:	
  41:	    static java.io.BufferedReader stdin = 
  42:	        new java.io.BufferedReader( new java.io.InputStreamReader(System.in) );
  43:	    static java.io.PrintStream stdout = System.out;
  44:	    static java.io.PrintStream stderr = System.err;     
  45:	}
echoサービスのクライアント と同様に、Socket から BufferedReader と PrintStream を生成している。 そして、readLine() や println() により通信を行っている。
Last updated: 2011/06/06 15:32:49
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>