筑波大学 システム情報系 情報工学域 新城 靖 <yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~syspro/2017/2017-05-31
/http-server-java.html
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~syspro/2017/
http://www.coins.tsukuba.ac.jp/~yas/
1: /* 2: HttpServerSingle.java -- 常に同じ内容を返す HTTP サーバ(Java版, スレッドなし) 3: ~yas/syspro/ipc/HttpServerSingle.java 4: Created on 2017/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:引数として、ポート番号を取る。
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() メソッドで 行われる。
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()参照。
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: }
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: }
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: }
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: }
\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: