筑波大学 システム情報系 情報工学域
新城 靖
<yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~syspro/2017/2017-05-31
/echo-server-java.html
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~syspro/2017/
http://www.coins.tsukuba.ac.jp/~yas/
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: {
14: if( argv.length != 1 )
15: {
16: stderr.printf("Usage: %% java EchoServerSingle port\n");
17: System.exit( -1 );
18: }
19: int portno = Integer.parseInt( argv[0] );
20: echo_server_single( portno );
21: }
22:
引数として、ポート番号を取る。
23: public static void echo_server_single( int portno ) throws IOException
24: {
25: ServerSocket acc = new ServerSocket( portno );
26: print_my_host_port( portno );
27: while( true )
28: {
29: stdout.printf("accepting incoming connections (hash== %s) ...\n",
30: acc.hashCode());
31: Socket com = acc.accept();
32: tcp_peeraddr_print( com );
33: EchoServerWorker esw = new EchoServerWorker(com);
34: esw.run();
35: }
36: }
echo_server_single() は、 引数で与えられたポート番号を使って接続要求受付用ポー トを作成し、それに対応した ServerSocket のオブジェクトを返す。このオブ ジェクトは、Socket のオブジェクトとは異なり、そまままでは通信に用いる ことはできない。
print_my_host_port() は、telnet で接続する時のヒントを表示する。
サーバのプログラムの特徴は、内部に無限ループを持っていることである。 サーバは、普通の状態では、終了しない。
accept() は、接続要求を待つメソッドである。クライアントから接続が来る まで、システムコールを実行したまま止まっているように見える。接続要求が 届くと、TCP/IP通信路の開設され、通信用ポートに対応したSocket クラスの オブジェクトが返される。このオブジェクトは、クライアント側と同様に getInputStream() や getOutputStream() により入出力可能なストリームを作 り出すことができる。
tcp_peeraddr_print() は、通信相手の IP アドレスとポート番号を表示する関数である。
以後の仕事は、EchoServerWorker というクラスのオブジェクトを作成して行 わせている。コンストラクタでは、Socket クラスのオブジェクトを渡してい だけであり、実際の処理は何も行われない。実際の処理は、run() メソッドで 行われる。
37: public static void print_my_host_port( int portno )
38: throws UnknownHostException
39: {
40: InetAddress ia = java.net.InetAddress.getLocalHost();
41: String hostname = ia.getHostName();
42: stdout.printf("run telnet %s %d\n", hostname, portno );
43: }
44: public static void tcp_peeraddr_print( Socket com )
45: {
46: InetSocketAddress isa =
47: (InetSocketAddress)com.getRemoteSocketAddress();
48: InetAddress ia = isa.getAddress();
49: String peerhostaddr = ia.getHostAddress();
50: int peerportno = isa.getPort();
51: stdout.printf("connection (hash== %s) from %s:%d\n",
52: com.hashCode(), peerhostaddr, peerportno );
53: }
54: static java.io.BufferedReader stdin = 55: new java.io.BufferedReader( new java.io.InputStreamReader(System.in) ); 56: static java.io.PrintStream stdout = System.out; 57: static java.io.PrintStream stderr = System.err; 58: }
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() // echo_receive_request_and_send_reply()
17: {
18: try
19: {
20: InputStream in = com.getInputStream();
21: OutputStream out = com.getOutputStream();
22: String line;
23: while( (line = echo_receive_request(in))!= null )
24: {
25: stdout.printf("received (com hash==%s) %d characters, [%s]\n",
26: com.hashCode(), line.length(),line );
27: echo_send_reply( line, out );
28: }
29: stdout.printf("connection (com hash==%s) closed.\n", com.hashCode());
30: in.close();
31: out.close();
32: com.close();
33: }
34: catch( IOException e )
35: {
36: stderr.printf("%s\n", e );
37: }
38: }
39: public static String echo_receive_request( InputStream is )
40: throws IOException
41: {
42: return( readLineIS(is) );
43: }
44: public static void echo_send_reply( String line, OutputStream out )
45: throws IOException
46: {
47: printfOS( out, "%s", line );
48: }
49:
echoサービスのクライアント
と同様に、
readLineIS() や
printfOS() により
メッセージの受信と送信を行っている。
$ cp ~yas/syspro/ipc/EchoServer{Single,Worker}.java .
$ ls *java
EchoServerSingle.java EchoServerWorker.java
$ javac EchoServerSingle.java EchoServerWorker.java
$ ls *class
EchoServerSingle.class EchoServerWorker.class
$ java EchoServerSingle
Usage: % java EchoServerSingle port
$ java EchoServerSingle 1231
run telnet crocus30.coins.tsukuba.ac.jp 1231
accepting incoming connections (hash== 2039470468) ...
connection (hash== 1813126941) from 130.158.86.170:49973
received (com hash==1813126941) 5 characters, [abc
]
received (com hash==1813126941) 5 characters, [def
]
received (com hash==1813126941) 5 characters, [ghi
]
connection (com hash==1813126941) closed.
accepting incoming connections (hash== 2039470468) ...
^C
$
クライアント側
$ telnet crocus30 1231
Trying 130.158.86.170...
Connected to crocus30.coins.tsukuba.ac.jp.
Escape character is '^]'.
abc
abc
def
def
ghi
ghi
^]
telnet> quit
Connection closed.
$