################################################################################ ●select()でブロッキングを回避する ################################################################################ *Solarisでのselectのmanはman -s 3c select にある。 1.ブロッキング send()やrecv()などでブロッキングが発生することは、重大な問題となります。 そこでプログラムが停止してしまうからです。 これを回避するためにselect()で送信/受信の準備完了を検出します。 select()は、ソケットの集合を引数に渡すと、受信可能なソケットの集合、送信可能な ソケットの集合、エラーが発生しているソケットの集合を返す機能を持っています。 ソケットの集合の操作の仕方を理解することが必要です。 2.ソケットの集合 ソケットの集合はfd_setという型にtypedefされています。 fd _setを宣言したら、FD_ZERO()を使って初期化して下さい。 @初期化 FD_ZERO(fd_set *fds) fds:空集合にしたいfd_setへのポインタ FD_ZERO()の実体はマクロで返値はありません。 Aソケットの集合fd_setにソケットを加えるにはFD_SET()を使います。 FD_SET(int s, fd_set *fds) s:追加したいソケット fds:sを追加するfd_setへのポインタ FD_SET()の実体はマクロで返値はありません。 Bソケットの集合fd_setからソケットを取り除きたい場合は、FD_CLR()を使います。 FD_CLR(int s, fd_set *fds) s :除外したいソケット fds:sを除外するfd_setへのポインタ FD_ZERO()の実体はマクロで返値はありません。 Cあるソケットがfd_setにあるか調べるには、FD_ISSET()を使います。 FD_ISSET(int s, fd_set *fds) s :元であるか調べたいソケット fds: sを元に持つか調べたいfd_setへのポインタ 戻り値は、sがある場合0以外の値、ない場合は0です。 3.select() int select( int nfds,fd_set *rfds, fd_set *wrds, fd_set *efds, struct timeval *timeout); nfds: rfds、wfds、efdsのうちで、最も値の大きいソケット+1 rfds :受信可能か調べるソケットの集合 wfds: 送信可能か調べるソケットの集合 efds: 例外が発生していないか調べるソケットの集合 timeout:select()がタイムアウトする時間の指定 nfdsに正しい値を与えなければ、select()は誤動作します。最大値に+1すること。 rfds、wfds、efdsに同じポインタを与えることはできません。 select()は、実際に受信可能、送信可能、エラーが発生しているソケットを、これら 3つの集合を直接書き換えることによって、知らせて来ます。 TCP接続において、listen()してあるソケットがaccept()可能か調べたい場合は、その ソケットをrfdsに追加して下さい。 select()は与えられたソケットの集合を監視し、どれかのソケットが受信可能、送信 可能、エラー発生になるまで処理をブロックします。 しかし、timeoutによってブロッキングの最大待機時間を指定でき、時間0を指定すれ ば、まったくブロックしません。 尚、NULLを与えれば、永久に待機し続けます。 timeval構造体は以下の型で、sys/time.hに定義されています。 struct timeval { long tv_sec; //秒 long tv_usec; //マイクロ秒 } select()の戻り値は、3つの集合に含まれるソケットの総和、タイムアウトしたときは 0、 select()の実行そのものにエラーが発生した場合は-1です。 UNIX系OSの場合、select()で監視できるのはソケットだけに限らず、キー入力やパイプ も fd_setに加えることができます。 4.ソケットを使う場合の注意(UNIX系OS) 接続が切れてしまったソケットに対して、送受信などのアクセスを行うと、関数の戻り 値がエラーになるだけでは無く、SIGPIPEが発生します。 SIGPIPEのデフォルト動作は、プログラムの強制終了です。通常はSIGPIPEをsignal()で トラップし、recv()が無事に-1を戻せるようにする必要があります。 またUNIXでは、ソケットはファイルディスクリプタを使うので、サーバプログラムを作 る場合は limitにも注意する必要があります。