【Java】データグラムソケット通信 part1【試験対策】

NO IMAGE

Javaでソケット通信に関するソースコードを記述する試験があるので,解説してみます.

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

開発環境は「Eclipse」,

バージョンは「Oxygen.2 Release (4.7.2)」です.

データグラムソケット

設問

労働基準法では,強風時(10分間の平均風速が毎秒 10m 以上)には高さ 2m 以上の箇所での作業を禁止している.ある会社では,作業現場に風速計発信器を設置して常に風速を遠隔監視しており,風速 10m 以上を観測した場合に作業中止を指示する.この風速計発信器は,風杯による風速感部と光センサによる検出部,信号変換部および伝送ケーブルにより構成され,微風(1m/s)から強風(60m/s)までを毎秒測定できる.測定した風速は遠隔監視装置へ送信される.風速を遠隔監視する以下の送受信プログラムを各々作成しなさい.

☆送信側

作業現場に風速計発信器を設置(送信側)したことを想定する.風速計発信器(送信側)は遠隔監視装置(受信側)へネットワークを接続し,現場の風速情報を伝達する.

※風速計発信器を想定した0~11(風速)までの乱数発生アルゴリズムを作成しなさい.

※情報の送信間隔は,上記シナリオ内部にヒントが隠されている.

☆受信側

遠隔監視装置(受信側)は定期的に送られてくる風速情報を受信し,コンソールへと表示する.風速が 10 m/s 超えが観測されたときは,コンソールへ「Stop working」と受信側の時刻を表示する.

整理

本来であれば,上記設問通りに設計していくわけですが,

既に要点がまとまってるんですよね.

なので,要点に足りない情報を補足していきます.

最初に,送信側を見ていきます.

送信側は風況データを送信します.

風速の乱数発生には,Randomクラスを使う.

※情報の送信間隔は,上記シナリオ内部にヒントが隠されている.

情報の送信間隔は,毎秒の風速を測定しているので1秒でいいです.

プログラムの待機には,Thread.sleep(ミリ秒);を使う.

送信側は,1秒間隔で常に情報を送り続けるので,無限ループ内で処理.

次に,受信側を見ていきます.

受信側は,送信側から送られてきたデータを元に処理をします

送信側から,1秒間隔で無限ループで常に情報を受け取るので,こちらも無限ループ内で処理.

10以上の数値を受け取ったら,コンソールで「Stop working」と受信側の時刻を表示.

ざっくり説明するとこんな感じですが,

ソケット通信に関しては未だノータッチなので,

コーディングで詳しく見ていきます.

環境

ここから先は,「Eclipse」を使う事を前提に説明していきます.

画面上部のファイルから,新規→Javaプロジェクトの順に選択する.

プロジェクト名を決めて完了をクリックする.

(保存場所を変更したい場合は,「デフォルト・ロケーションを使用」のチェックボックスのチェックを外し,参照で場所を決める.)

ここではプロジェクト名は「training_exam」とします.

画面左側のパッケージ・エクスプローラーに作成したプロジェクトが表示されるので,

右クリックして,パッケージの順に選択する.

名前を決めて完了をクリックする.

ここではパッケージ名は「exam1」とします.

srcフォルダの中に作成したパッケージ(exam1)が確認できたらOKです.

送信側クラス

先ほど作成したパッケージを右クリックして,新規→クラスの順に選択する.

名前を決めて,mainメソッドを持つクラスなので「public static void main(String[] args)」のチェックボックスにチェックを入れて完了をクリックする.

ここではクラス名を「DatagramSender」とします.

これで準備は完了です.

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

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

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

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

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

この処理は何かとエラーが発生するので,try-catch文で例外処理をします.

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

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

UnknowsExceptionクラスは,Oracle Docsでは,ホストのIPアドレスが判定できなかった場合にスローされると書いてありますが,

単純にホスト名からIPアドレスが見つからなかったと考えていいです.

ちなみに,波線が出た箇所にマウスカーソルを当てると「周囲の try に catch 文節を追加」という項目が出てくるので,

これをクリックする事で,自動的に例外処理が記述されます.(この機能によって,エラーの対象クラスがわからなくても記述できます.)

次に,データグラムソケットとパケットを定義します.

ソケットを生成する際に,エラーが発生するかもしれないので,例外処理も記述します.

SocketExceptionクラスは,ソケット作成中にエラーが発生したときにスローします.これはそのままですね.

ここまで記述できたら,下準備は終わりです.

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

while文の中身が今回の内容です.

ランダムクラスを生成する.

ランダムクラスからint型の乱数0~11を取得する.

int型をbyte型配列に変換する.

整理したデータから,送信する為のパケットを生成する.

1000ミリ秒待機後,パケットを送信する.

catch文を2つ追加していますが,

IOExceptionはsock.send(pack)に,

InterruptedExceptionはThread.sleep(1000)に対応しています.

最後にソケットを閉じていない所に違和感がある人もいると思います.

今回はデータグラムソケット(UDP)による通信なので,

受信側からのACK情報を受け取る事ができないので仕方ないです.(通信終了タイミングを考慮できない.)

受信側クラス

作成方法は送信側クラスと同じなので省略します.

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

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

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

サイズは適当に256にしておきます.

次に,データグラムソケットとパケットを定義する.

送信側クラスとの違いは,宛先IPアドレスが不要である事と,

パケットは,受信した時のデータを格納するbyte型配列の変数(バッファー)を用意しておく必要があります.

また,受信するデータサイズを指定する必要があります.

下準備はこれで終わりです.

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

while文の中身が今回の内容です.

最初のsock.receive(pack);では,パケットを受信するまで待機する.

パケットを受信後,pack.getData();でデータを取り出してdata変数に格納する.

data変数はbyte型なので,int型に変換して,コンソールへ出力する.

wp変数の数値が10以上の時に「Stop working [現在の時刻]」をコンソールへ出力する.

実行

実行順序は,受信側クラス(DatagramReceiver)→送信側クラス(DatagramSender)の順に実行します.

実行結果(受信側)

こんな感じに出力されていればOKだと思います.

次回part2はストリームソケット通信の試験問題を扱います.