チャットサーバとクライアント


チャットサーバ

複数のクライアントを管理するために ArrayListクラスを使います。 このクラスはthread safeではないので、ArrayListのインスタンスに 変更を加える(要素を加える、要素を削除する、など)場合は synchronizedを使って同期する必要があります。

このチャットサーバに、前に作成した RunTelnetClient クラスを 使って接続してみましょう。複数の「ターミナル」ウィンドウを開いて、 それぞれで RunTelnetClientを動作させます。

$ java RunTelnetClient localhost 8888
それぞれの「ターミナル」ウィンドウで入力すると、他のウィンドウにも 届くのがわかるはずです。 日本語を入力しても正しく動作することを確認して下さい。

クライアント全員にメッセージを送るには、 複数のクライアントを管理するArrayListを使ってイテレータを取り出し、 順に送っていきます。 ところが、イテレータのnext()メソッドは元のArrayListオブジェクトが 変更されるとExceptionを発生してしまいます。 これを避けるには、「変更する場合には一旦元のListを コピーをしてから書き込みを行う」 java.util.concurrent.CopyOnWriteArrayListクラスを使うべきです。














RunChatServer.javaの実行例
$ javac RunChatServer.java
$ java RunChatServer
accepted from /127.0.0.1
clients.size() = 1
accepted from /127.0.0.1
clients.size() = 2
accepted from /127.0.0.1
clients.size() = 3


実行例(クライアント1)
$ java TelnetClientAll localhost 8888
apple
2:hello
こんにちは
3:3人目です。
SERVER:clients.size() = 2
SERVER:clients.size() = 1
    ←Ctl-Cで強制終了


実行例(クライアント2)
$ java TelnetClientAll localhost 8888
hello
1:こんにちは
3:3人目です。
SERVER:clients.size() = 2
   ←Ctl-Cで強制終了


実行例(クライアント3)
$ java TelnetClientAll localhost 8888
3人目です。
     ←Ctl-Cで強制終了


コンピュータネットワーク 演習


提出〆切は次回の講義の開始時刻です。


課題7c

提出先 http://ynitta.com/class/network/local/handin/list.php?id=kadai7c
提出ファイル変更したChatHandler.java
コメント欄 3人以上でチャットしたときの、自分のクライアントの出力結果。 コマンドが正しく処理されていることを確認できるログを コピー&ペーストで貼りつけて置くこと。

チャットサーバを動作させてみましょう。 3人以上でオンラインの会話をして下さい。

ChatHandler.javaでは、あるクライアントがサーバに送った 文字列はすべてサーバが他のクライアントに転送していました。 ChatHander.javaを変更して、サーバ側に次の機能を持たせて下さい。

追加すべき機能: 「文字の先頭が":"である文字列を送った場合は、それが サーバへのコマンドである」と解釈される。 コマンドの種類は以下のとおり。

コマンド形式機能
show_id:show_id:

このコマンドを送ってきたクライアントに、そのクライアントのidを文字列として返す。

list:list:

サーバに接続しているクライアントのidを返す。 ただし、このコマンドを送ってきたクライアントのidは含めない。 idは整数で表されるが、間にスペース1個をはさんだ文字列として返すこと。 文字列に余分なスペースは含めてはならない。

上記以外:文字列:文字列

コマンドを送ってきたクライアントにだけ":unknown_command:"という 文字列を返す。

クライアントがサーバに送った文字列の先頭の文字が':'であれば、 サーバへのコマンドであると解釈してよい。 クライアントAからサポートしていないコマンドが送られてきた場合は ":unknown_command:"という文字列をクライアントAに返す。 「サポートしているコマンドであるが、パラメータが足りない、 パラメータのタイプが違う」などの場合は":format_error:"という 文字列をクライアントAに返す。

パラメータが余っている場合は、余ったパラメータは無視して構わない。 たとえば":list:3,5,6"というコマンドが送られてきた場合は"3,5,6" という文字列は無視して構わない。


課題7d

提出先 http://ynitta.com/class/network/local/handin/list.php?id=kadai7d
提出ファイル変更したChatHandler.java
コメント欄 内緒話機構をつけて、3人以上でチャットしたときの クライアントの出力結果。 コマンドが正しく処理されていることを確認できるログを コピー&ペーストで貼りつけて置くこと。

さらに":talk_to:"コマンドを実装して下さい。

コマンド形式機能
talk_to:talk_to:数字:文字列

特定のクライアントだけに文字列を送る。いわゆる内緒話機能。

上記以外:文字列:文字列

コマンドを送ってきたクライアントにだけ":unknown_command:"と 文字列を返す。

":talk_to"コマンドにおいて存在しない相手を指定した場合は ":no_such_client:"を返すこと。

コマンド版RunChatServer.javaの実行例
$ java RunChatServer
accepted from /127.0.0.1
clients.size() = 1
accepted from /127.0.0.1
clients.size() = 2
accepted from /127.0.0.1
clients.size() = 3
1:abc
2:apple
3:red
2::show_id:
2::list:
2::talk_to:1:orange


実行例(クライアント1)
$ java RunTelnetClient localhost 8888
abc
2:apple
3:red
2:orange


実行例(クライアント2)
$ java RunTelnetClient localhost 8888
1:abc
apple
3:red
:show_id:
2
:list:
1 3
:talk_to:1:orange


実行例(クライアント3)
$ java RunTelnetClient localhost 8888
1:abc
2:apple
red