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