第8講:サーバ・クライアント間の通信を行う

その2 通信を行うプログラム「飲酒可否判定システム」を作成する

 ここでは、その1で学習したクライアント・サーバ通信を行う方法を実践するために、簡単なサンプルプログラムを作成してみます。今回はクライアントによって送信された年齢を元にサーバが飲酒の可否を判断しその結果をクライアントに送信するという「飲酒可否判定システム」を課題として取り上げます。

(1)「飲酒可否判定システム」におけるサーバ・クライアントの役割と         データのやりとりの様子

 「飲酒可否判定システム」を設計するためには、まずサーバとクライアント間でどのようなデータのやりとりをさせたいのかを決めておかなければなりません。さらにそのためには、このシステムにおけるサーバとクライアントそれぞれの役割を明確にしておく必要があります。そこで今回は、サーバ、クライアントに対してそれぞれ以下の役割を与えることにします。

サーバの役割
 サーバはクライアントから送信される年齢を表すデータを受信する。それに基づいて「飲酒可能/不可能」の判定を行う。判定結果を表すデータをクライアントに送信する。
クライアントの役割
 クライアントはユーザーから年齢を聞き出し、サーバに対してそれを表すデータを送信する。サーバから送信された飲酒可否の判定結果を表すデータを受信する。そのデータをディスプレイに表示し、ユーザーに知らせる。

 それぞれの役割が明らかになったところで、今度はサーバとクライアントがどのような順序でどんなデータをやりとりするのかを、明らかにします。「まずどちらからどちらへどのようなデータが送信され、、、」といったことをあらかじめ決めておかなければ、正しいプログラムを書くことができないからです。今回のケースではどのようになるのでしょうか...。

 ということで、通信の様子は以下の図のようにまとめられます。

サーバ

待機

↑年齢を受信

(判定)

結果を送信↓

終了

クライアント

年齢を送信↑

待機

待機

待機

↓結果を受信

(2)プログラムの設計・1

 今度はサーバ、クライアントそれぞれのプログラムの設計を行います。今回の場合、それぞれのプログラムの骨格は(1)でまとめた通信の様子に従って決定されます。例えばクライアントの場合、「年齢を送信」したいのならばその前段階に「年齢」を読み込んでおく必要がありますし、判定結果をユーザーに知らせるのは当然「結果を受信」したあとになるわけです。このようにして考えてゆけば、それぞれのプログラムの骨格が明らかになってくるはずです。

 以上のように考えると、それぞれのプログラムの仕事の流れは次のようにまとめられます。

サーバのプログラム

1.通信の準備をする

2.年齢を受信する

3.飲酒の可否を判定する

4.判定結果を送信する

5.通信終了の合図を送る

クライアントのプログラム

1.通信の準備をする

2.年齢を読み込む

3.年齢を送信する

4.判定結果を受信する

5.判定結果を表示する

 あとはそれぞれの段階でどのような命令が必要になるのかを考えればよいのです。それが明らかになれば設計は終了、プログラムを書き始めます。しかし上記の各段階を実現するための命令のうち、いくつかにはまだ学習していない事項も含まれます。また少々の補足が必要な部分もあります。そこでつぎに、それらの事項の解説を行っておきます。

(3)プログラムの設計・2

 ここではそれぞれのプログラムを完成する上で必要な補足説明を行います。説明の便宜上、まずはクライアント、そのつぎにサーバの順で説明をします。

クライアントのプログラムについて
 1.通信を準備する: この部分については「その1」で学習しています。基本的にはSocketクラスをインスタンス化すればいいわけですが、その際引数として「ホストコンピュータ(サーバのプログラムが動いているコンピュータ)の名前」と「ポート番号」が必要となりました。今回の場合は「ホストコンピュータ名」はユーザーからキーボードで入力してもらい、「ポート番号」についてはあらかじめ「8000番」という番号を決めておきます。通常若い番号は何らかの用途ですでに使われている可能性があります。
 2.年齢を読み込む: この部分はユーザーからのデータの読み込みなので、キーボードを利用します。読み込んだ年齢は一旦キャストして、整数型の変数に記憶しておきます。
 3.年齢を送信する: データの送受信の方法は「その1」で学習したとおりです。ObjectOutputStreamを利用する場合、やりとりできるデータの型は「任意のクラスのインスタンス」でした。ここでひとつ注意しなければならないことがあります。キーボードから読み込んだ年齢は整数型の変数に記憶されていることになっていますが、この「整数型」は、「クラスのインスタンス」ではありません
 ObjectOutputStreamはどんなクラスのインスタンスでも送信することができるのですが、「整数型(int)」や「文字型(char)」などのデータには対応していません。そこで、一旦整数型のデータを「Integerクラス」のインスタンスに変換します。この「Integerクラス」は主に整数値を「クラスのインスタンス」として扱いたいときに利用されます。方法は、変換したい整数型データを引数として与えて「Integerクラス」のインスタンス化をすればよいのです。そしてObjectOutputStreamからは、ここで生み出された「Integerクラス」のインスタンスを送信します。
 4.判定結果を受信する: これも「その1」で学習したとおりです。今回の「判定結果」は、「OK」または「NO」という文字列が送られてくるということにしておきます。ちなみに「文字列型」のデータは「整数型」とちがい「Stringクラス」のインスタンスとして定義されているため、ObjectInput(Output)Streamで直接送受信可能です。
 5.判定結果を表示する: 受信した文字列をディスプレイに表示する、ということです。

サーバのプログラムについて
 1.通信の準備をする: サーバ側の通信準備も「その1」で学習しました。クライアントのところでも触れましたが、今回の場合ポート番号は「8000」にしておきます。
 2.年齢を受信する: クライアントの部分での解説の通り、「年齢」は「Integerクラス」のインスタンスとしてやってきます。ですが受信した「年齢」をつぎの「3.飲酒の可否を判定する」で利用する際には、先回りになりますが、「整数型」で利用することになります。そこで、一旦「Integerクラス」として受け取った「年齢」を「整数型」に戻してやらなければなりません。その方法として「Integerクラス」の
「intValueメソッド」を利用します。このメソッドが「Integerクラス」のインスタンスから起動されると、インスタンスが生成されたときに引数として渡された整数型の値が返値として返されます。つまり、クライアント側で一旦整数型で記憶した「年齢」が返値として返ってくるわけです。それを代入文で受け取ってやればいいのです。
 3.飲酒の可否を判定する: ここでは受信した年齢に従って、飲酒可能を表す「OK」か飲酒不可能を表す「NO」のどちらかをクライアントに送るためのメッセージとして用意します。もう少し具体的にいうと、あらかじめ用意しておいたメッセージを記憶するための「String型」の変数に、年齢の値が20以上の場合と場合とそうでない場合で異なる文字列(「OK」または「NO」)を代入する、ということを行います。このようにある条件(この場合「整数型データ「年齢」の値が20以上か否か」)を設定し、その条件の判定結果が真か偽かによって異なる命令を実行させたい場合、「if文」によってそれを記述します。この「if文」は次のように記述します。

if ( 条件式 ){

命令文1;

}else{

命令文2;

}

 条件式はwhile文の終了条件と同様に記述します。例えば「整数型変数「age」の値が20以上の場合」を表すならば、「age >= 20」と書くわけです。そしてその条件が真の場合に実行させたい命令を、その直後の{}内に記述します(上の図では「命令文1」)。また偽の場合に実行させたい命令は最初の{}の直後に「else{}」という形であらためて{}を作りその中に記述します(上の図では「命令文2」)。このように記述することで、あらかじめ用意された二通りの命令のどちらか一方を条件に従って選んで実行させることができるのです。
 このように「if文」は、それ自体が能動的な命令を表すのではなく、命令の実行順序をあらわす記述です。これと同様の「命令の実行順序をあらわす記述」として私たちはすでに「while文」を学習しています。この「命令の実行順序をあらわす記述」のことを一般に「制御文」と呼び、プログラム中に記述される複数の命令の実行順序のことを「制御構造」と呼びます。
 この「制御構造」は一般に3種類のものが存在します。まず制御文を用ず上から書かれた順に命令が実行される場合のことを「順次」といいます。そして「while文」が用いられるときのようにある条件の範囲内で同じ命令が繰り返し実行されるような場合を「繰り返し」、さらに「if文」のように用意された複数の命令のいずれかが条件により選ばれて実行される場合を「分岐」とよびます。
 どんなに複雑な処理も、この3つの制御構造を組み合わせることで記述することができるのです。
4.判定結果を送信する: この場合送信すべき「判定結果」とは「OK」か「NO」という文字列です。クライアントの時に少し触れましたが、この「文字列型」をあらわす「String」とは実際にはクラスの名前なのです。「””」で囲んだ中に記述された文字を代入することでインスタンス化が行われるという少々特殊なクラスです。したがって「年齢」の時と違い、ここでは「判定結果」を直接送信することができます。方法は「その1」を参照して下さい。
5.通信終了の合図を送る: これについては、その1で解説しました。今回のケースもサーバの側が通信終了の合図を送ります。

 ということで、サーバ、クライアント、双方のプログラムについての解説が終わりました。あとは、この解説を参考に設計・実装を行ってみて下さい。なお、今回作成するサーバのクラス名はSampleServer、クライアントはSampleClientとしておきましょう。

>>解答例のプログラム(サーバ) 

>>解答例のプログラム(クライアント)


リンク:

<全体のトップページ>

     |

<第8講のトップページ>

     |-------------------------|

<第8講・その1>        <第8講・その2>