マルチクライアントプログラム
これまでのプログラムは、サーバーとクライアントで1対1の通信を行うものでした。 今度は、複数のクライアントを同時に扱うことのできるようにサーバを拡張します。 INETドメインでSTREAM型のプログラムを使います。 では、さっそくプログラムの例を見てみましょう。クライアントプログラムの方は、 INETドメインの解説で用いたのと全く同じものです。まず、socket descriptorとしてs[SOCK_MAX+1]を定義しています。 SOCK_MAXは、自分でdefineしたもので、とりあえず5としてあります。 すなわち、全部で六つのソケットを用意したことになります。
mserverではこれらの六つのソケットを、
s[0] 新しい接続要求を待つためのソケット s[1..4] クライアントと接続され実際に通信をおこなうためのソケット s[5] 接続拒否に使うの一時接続ソケットとして使うことにします。また、s[i]の値がUNUSEDの場合は、そのソケット は使われていないことを表すことにします。次にfd_set型の変数を定義します。今回はreadfdsという名前にします。 これは、後で述べるselectシステムコールで利用します。
接続を待つソケット(s[0])に関しては、socket、bind、listenシステムコール までの手順はiserverの時と全く同じです。
ここで、マルチクライアントで起こりうることを考えてみましょう。
最初のクライアントの接続は、acceptしてあげればうまくいきます。 しかし、次のクライアントのために、s[0]は再度acceptシステムコールで待ち状態 にしなければなりません。しかしながら、acceptシステムコールで 処理をブロックしてしまった場合、最初に繋いだクライアントの応対をする ことができなくなります。
そこで使うのがselectシステムコールです。これは、複数のソケット に対してのメッセージ待ちを可能にします。selectシステムコールでは 検査対象のソケットを指定し、そのうちのどれかにメッセージが到着する までブロックします。そしてどれかにメッセージが到着すると、どこに 届いたかを教えてくれます。
s[0], s[1]のどっちかにメッセージが来たら知らせるようにselectシステムコールを 設定し、処理が戻ると例えばs[1]にメッセージが到着しているということが わかります。ですから、それにしたがってメッセージの到着したソケット に対して処理を行なえばいいわけです。
selectシステムコールを使うにはfd_setという型の変数を使います。この変数で 検査対象となるソケットをあらかじめ指定するわけです。 このfd_set型の変数は直接操作せず、マクロを使って操作します。
まず、FD_ZERO(& readfds)でリストをクリアしておきます。そのあと、 検査対象はFD_SET(追加したいソケット,& readfds)を使って設定していきます。 selectシステムコール本体は
select(FD_SETSIZE, & readfds, NULL, NULL, NULL)となります。FD_SETSIZEはシステムで許される最大の個数をさします。 検査しないものにはNULLを指定します。 最後の引数はタイムアウト時間ですが、NULLを設定すると ready状態になるまでブロックされます。selectシステムコールから処理が戻ると、readfdsにはFD_SETで設定したもの のうち、メッセージが到着しているものだけ、ビットがセットされて返ってきます。 これをFD_ISSET(調べるソケット, & readfds)を使ってどれがセットされているのか 調べます。
mserverでは、s[1〜max未満]のソケットにメッセージが到着しているかどうかを 調べ、到着している時は大文字に変換した後、接続中のクライアントすべてに メッセージを送り返しています。
ソケットs[0]は接続要求のくるソケットですから、このソケットにメッセージ が到着しているときにはacceptシステムコールで接続を受け付けます。また、 接続を拒否する場合には、一旦acceptしたあとに、ソケットをcloseして しまうという方法を使います。
以上でマルチクライアントのサーバが書けます。このmserverでは一度使って しまったソケットを再利用していませんが、これをちゃんと再利用するように すれば4クライアントのサーバとなります。
◆実行方法
- まず、何台かのマシンにログインします。(同じマシン上に複数のウィンドウを開いて 使っても構いません)
- 1台のマシンで、
# ./serverとして先にサーバーを起動します。
- 次に残っているマシンで、
# ./client サーバー名として、クライアントを起動します。
- クライアントのマシンで文字を打ち込むと、大文字に変換されて表示されます。
- 同時に複数のマシンでクライアントを起動しても、同じようにサーバーが処理してくれます。
![]()
![]()
![]()