複数のクライアントを管理するために ArrayListクラスを使います。 このクラスはthread safeではないので、ArrayListのインスタンスに 変更を加える(要素を加える、要素を削除する、など)場合は synchronizedを使って同期する必要があります。
このチャットサーバに、前に作成した RunTelnetClient クラスを 使って接続してみましょう。複数の「ターミナル」ウィンドウを開いて、 それぞれで RunTelnetClientを動作させます。
$ java RunTelnetClient localhost 8888それぞれの「ターミナル」ウィンドウで入力すると、他のウィンドウにも 届くのがわかるはずです。 日本語を入力しても正しく動作することを確認して下さい。
クライアント全員にメッセージを送るには、 複数のクライアントを管理するArrayListを使ってイテレータを取り出し、 順に送っていきます。 ところが、イテレータのnext()メソッドは元のArrayListオブジェクトが 変更されるとExceptionを発生してしまいます。 これを避けるには、「変更する場合には一旦元のListを コピーをしてから書き込みを行う」 java.util.concurrent.CopyOnWriteArrayListクラスを使うべきです。
RunChatServer.javaの実行例 |
|
実行例(クライアント1) |
|
実行例(クライアント2) |
|
実行例(クライアント3) |
|
提出〆切は次回の講義の開始時刻です。
提出先 | 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" という文字列は無視して構わない。
提出先 | 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の実行例 |
|
実行例(クライアント1) |
|
実行例(クライアント2) |
|
実行例(クライアント3) |
|