【Java】ストリームソケット通信 part2【試験対策】

NO IMAGE

part2ではストリームソケット通信について扱います.(単なる試験問題の対策なので,内容についてはいつかやりたいと思います.)

ストリームソケット通信

設問

ネットワークを活用して各地の協力者から天候情報を集計するシステムを構築します.以下のシナリオを実現するプログラムを作成しなさい.

ClientがServerへ接続します.

ServerからClientへ,質問が送信されます.

送信される質問「How is the weather? 0:Sunny,1:Cloudy,2:Rainy,3:Snowfall」

Clientは受信した質問をコンソールへ表示します.

コンソール:How is the weather? 0:Sunny,1:Cloudy,2:Rainy,3:Snowfall

Clientはコンソールから回答のコマンドを入力します.

ClientからServerへ,回答と送信側の時刻が送信されます.

Serverは受信した回答と送信側の時刻をコンソールへ表示します.

※Serverはマルチスレッド化しなさい.

 

整理

今回もほぼ要点がまとまっているので書いていない所だけ補足していきます.

ServerからClientへ,質問が送信されます.

送信される質問「How is the weather? 0:Sunny,1:Cloudy,2:Rainy,3:Snowfall」

Clientは受信した質問をコンソールへ表示します.

コンソール:How is the weather? 0:Sunny,1:Cloudy,2:Rainy,3:Snowfall

基本的には,ストリームソケット通信もbyte型配列でデータを送受信する事になるので,

byte型とString型の変換ができるかが問われています.

byte型→String型はnew String(byte型配列),

String型→byte型はString.getBytes()で変換できます.

Clientはコンソールから回答のコマンドを入力します.

さり気なくコマンドと書いてあるので,コマンド処理を記述する必要があります.

switch-case文を使うと楽に記述できます.

※Serverはマルチスレッド化しなさい.

マルチスレッド化と言う事は,一斉通信をするという事なので,送信先の情報がわかるといいと思います.

InetAddress.getHostAddress()で取得できるので,この情報を付加するだけです.

 

環境

part1で作成した「training_exam」プロジェクトの中に,「exam2」パッケージを作成します.(手順はpart1で説明しているので省略します.)

Clientクラス

Client側のクラスを作成します.

名前は「Client」とします.

最初に,必要な情報を定義していきます.

ソケット通信をする為には宛先IPアドレスとポート番号が必要なので,定義します.(データグラムソケット通信と同じです.)

ここでは自身のPC宛てに通信するので,IPアドレスは「localhost」にします.

ソケット通信は,byte型でデータを送受信するので,byte型の配列を定義します.

コマンド処理用のコマンドを定義します.

次に,通信の処理を書いていきます.

この処理は何かとエラーが発生するので,try-catch分で例外処理をします.(データグラムソケット通信と同じ.)

InetAddressクラスのgetByNameメソッドで,ホスト名(IPADR変数)からipアドレスを取得します.

また,その時の例外処理も記述します.

次に,ストリームソケット通信をする為のソケットを定義します.

先ほど定義したソケットから,入出力ストリームを宣言します.

ここまで記述できたら,下準備は完了です.

最初にまとめた事をコーディングしていきます.

先ほど宣言した入力ストリームから,サーバからのデータを受信する.

受信したデータをコンソールへ出力する.

コンソール:How is the weather? 0:Sunny,1:Cloudy,2:Rainy,3:Snowfall

キー入力された値から,switch-case文でそれぞれのコマンドに変換する.

送信するデータを整理する為に,文字列を定義する.

1文字目はコマンドデータを入れるので空白文字で空けておく.

時刻,送信元のIPアドレスを取得し,文字列に連結する.

文字列をbyte型配列に変換して,0番目に先ほど変換したコマンドを代入する.

最後にサーバへ送信して,ソケットを閉じる.

 

Serverクラス

Server側のクラスを作成します.

名前は「Server」とします.

最初の下準備は,Clientクラスと大した変わらないので,ざっくり説明します.

最初に,受信するポート番号,データ格納用のbyte型配列を定義します.

次に,コマンド処理用のコマンドを定義します.

次に,通信の処理を書いていきます.

ストリームソケット通信をする為のソケットを定義します.

当たり前ですが,Server側はサーバを建てるので,ServerSocketでソケット通信用のサーバを建てます.

先ほど定義したソケットから,入出力ストリームを宣言します.

ここまで記述できたら,下準備は完了です.

最初にまとめた事をコーディングしていきます.

先ほど宣言した出力ストリームから,Clientへデータを送信する.

送信される質問「How is the weather? 0:Sunny,1:Cloudy,2:Rainy,3:Snowfall」

while文にしているのは,後々マルチスレッド化で動作を確認している為です.

入力ストリームから,Clientからデータを受信する.

switch-case文でコマンドから,天気情報の文字列へ変換する.

変換された文字列,受信した送信側時刻と送信側IPアドレスをコンソールへ出力する.

ループを抜けた場合は,ソケットを閉じてプログラムを終了する.

 

マルチスレッド化

先ほど記述したServerクラスを元にマルチスレッド化します.

クラス名は「StreamMultiThread」とします.

マルチスレッド化するので,Threadクラスを継承します.

runメソッドをオーバーライドし,中の処理はServerクラスのmainメソッドの処理をコピーして貼り付けます.

このクラスをインスタンス化させる時に,ソケットの情報を更新したいので,

フィールドにSocketクラスの変数を宣言します.

また,コンストラクタで引数を代入します.

runメソッド内のPORT変数,sv_sock変数,sock変数はコメントアウトしておきましょう.

StreamMultiThreadクラスはこれで完成です.

次に,Serverクラスを変更します.

マルチスレッドで動かす為に,while文で無限ループにしています.

StreamMultiThreadクラスのインスタンスを生成する時に,引数にsock変数を渡して,コンストラクタで代入します.

startメソッドで処理を開始します.

 

実行

実行順序は,Serverクラス→Clientクラスの順に実行します.

実行結果(Client)

実行結果(Server)

Client側の処理を無限ループして,何度か送信してみます.

実行結果(Client)

実行結果(Server)

この試験,リファレンス見ないで書かないといけないらしいんですよね・・・