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

                                       筑波大学 システム情報系 情報工学域
                                       新城 靖
                                       <yas@cs.tsukuba.ac.jp>

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

HTTPサーバ(Java版)

HttpServerSingle.java

HttpServerSingle.javaは、HTTP で要求を受け取り、 HTTで常に一定の内容を返すサーバである。

main()

   1:	/*
   2:	  HttpServerSingle.java -- 常に同じ内容を返す HTTP サーバ(Java版, スレッドなし)
   3:	  ~yas/syspro/ipc/HttpServerSingle.java
   4:	  Created on 2018/07/23 22:09:56   5:	*/
   6:	
   7:	import java.net.*;
   8:	import java.io.*;
   9:	
  10:	class HttpServerSingle
  11:	{
  12:	        public static void main(String argv[]) throws IOException 
  13:	        {
  14:	                if( argv.length != 1 )
  15:	                {
  16:	                        stderr.printf("Usage: %% java HttpServerSingle port\n");
  17:	                        System.exit( -1 );
  18:	                }
  19:	                int portno = Integer.parseInt( argv[0] );
  20:	                http_server_single( portno );
  21:	        }
  22:	
引数として、ポート番号を取る。

http_server_single()

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

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

print_my_host_port() は、Web ブラウザで接続する時のヒントを表示する。

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

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

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

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

print_my_host_port_http()

print_my_host_port_http() は、Web ブラウザや telnet で接続する時のヒントを表示する。
  35:	        public static void print_my_host_port( int portno ) 
  36:	                throws UnknownHostException
  37:	        {
  38:	                InetAddress ia = java.net.InetAddress.getLocalHost();
  39:	                String hostname = ia.getHostName();
  40:	                stdout.printf("open http://%s:%d/path\n", hostname, portno );
  41:	        }
print_my_host_port()参照。

HttpServerWorker.java

HttpServerWorker run()

   1:	/*
   2:	        HttpServerWorker.java -- 文字列を送受信するサーバ/ワーカ(TCP/IP, Java版)
   3:	        ~yas/syspro/ipc/HttpServerWorker.java
   4:	*/
   5:	
   6:	import java.net.*;
   7:	import java.io.*;
   8:	
   9:	public class HttpServerWorker implements Runnable
  10:	{
  11:	        Socket com ;
  12:	        HttpServerWorker( Socket com )
  13:	        {
  14:	                this.com = com ;
  15:	        }
  16:	        static int BUFFERSIZE = 1024;
  17:	        public void run() /* http_receive_request_and_send_reply() */
  18:	        {
  19:	                try
  20:	                {
  21:	                        InputStream in = com.getInputStream();
  22:	                        OutputStream out = com.getOutputStream();
  23:	                        if( http_receive_request( in ) )
  24:	                        {
  25:	                                http_send_reply( out );
  26:	                        }
  27:	                        else
  28:	                        {
  29:	                                http_send_reply_bad_request( out );
  30:	                        }
  31:	                        stdout.printf("Replied\n");
  32:	                        in.close();
  33:	                        out.close();
  34:	                        com.close();
  35:	                }
  36:	                catch( IOException e )
  37:	                {
  38:	                        stderr.printf("%s\n", e );
  39:	                }
  40:	        }

HttpServerWorker http_receive_request()

  41:	        boolean http_receive_request( InputStream in )
  42:	                throws IOException
  43:	        {
  44:	                String requestline;
  45:	                String rheader;
  46:	                requestline = readLineIS( in );
  47:	                if( requestline == null || requestline.length() <= 0 )
  48:	                {
  49:	                        stderr.printf("No request line.\n");
  50:	                        return( false );
  51:	                }
  52:	                requestline = chomp( requestline ); /* remove \r\n */
  53:	                stdout.printf("requestline is [%s]\n",requestline );
  54:	                while( (rheader=readLineIS( in )) != null )
  55:	                {
  56:	                        rheader = chomp( rheader ); /* remove \r\n */
  57:	                        if( rheader.compareTo("") == 0 )
  58:	                                break;
  59:	                        stdout.printf("Ignored: [%s]\n",rheader );
  60:	                }
  61:	                if( requestline.indexOf('<') >= 0 ||
  62:	                    requestline.matches(".*\\.\\..*") )
  63:	                {
  64:	                        stdout.printf("Dangerous request line found.\n");
  65:	                        return( false );
  66:	                }
  67:	                return( true );
  68:	        }

HttpServerWorker http_send_reply()

  69:	        void http_send_reply( OutputStream out )
  70:	                throws IOException
  71:	        {
  72:	                printfOS(out,"HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n");
  73:	                printfOS(out,"<html><head></head><body>hello.</body></html>\n");
  74:	        }

HttpServerWorker http_send_reply()

  75:	        void http_send_reply_bad_request( OutputStream out )
  76:	                throws IOException
  77:	        {
  78:	                printfOS(out,"HTTP/1.0 400 Bad Request\r\nContent-Type: text/html\r\n\r\n");
  79:	                printfOS(out,"<html><head></head><body>400 Bad Request</body></html>\n");
  80:	        }

chomp()

chomp() は、行末の \n\r を削除する関数である。 Perl や Ruby 等のスクリプト言語にも同名で類似の動作を行う関数がある。
  81:	        static String chomp( String str )
  82:	        {
  83:	                int len = str.length();
  84:	                if( len>=2 && str.charAt(len-2) == '\r' && str.charAt(len-1) == '\n' )
  85:	                {
  86:	                        return( str.substring( 0, len-2 ) );
  87:	                }
  88:	                else if( len>=1 && (str.charAt(len-1) == '\r' || str.charAt(len-1) == '\n') )           
  89:	                {
  90:	                        return( str.substring( 0, len-1 ) );
  91:	                }
  92:	                return( new String(str) );
  93:	        }
  94:	

その他

次の関数や変数は、 EchoServerWorker.java と同じ。 echoのクライアント側 とも同じ。
Last updated: 2018/05/27 17:02:19
Yasushi Shinjo / <yas@cs.tsukuba.ac.jp>