!!! 複数の入力を扱う '''あるいは,select (システムコール) の使い方''' !! 参考にするプログラム [serv.c|https://svn.cis.iwate-u.ac.jp/svn/csd/Examples/socket/serv.c] service関数 !! service 関数の動き サーバは, * 一人のクライアントからのメッセージを画面に表示 ** ソケット側のファイル識別子を read して, ** 標準出力のファイル識別子へ write. * 自身のキーボードからの入力をクライアントへ送信 ** 標準入力のファイル識別子を read して, ** ソケット側のファイル識別子へ write. のどちらかを,行います.ただし,その順番を決めてしまった場合, 入力データがないファイル識別子を read すると read は待ち状態に入り入力があるまで動き出しません. 待ちを生じさせないためには,入力データがあるかを確かめてから read する必要があります.それを行うのが select システムコールです. このように入力データの到着順によって入力を行うことを, 非同期入力と呼びます. !! service 関数の説明 8< struct fd_set >8 * 複数のファイル識別子の集合を表す構造体です. 8< struct fd_set mask, readfds; >8 * maskは入力を調べるファイル識別子集合 * readfds は入力でーたがあったファイル識別子集合 8< struct timeval timeout; >8 * 待ち合わせ時間設定用構造体 8< FD_ZERO(&mask); >8 * maskのファイル識別子集合を空にします. 8< FD_SET(0, &mask); /* stdin */ FD_SET(s, &mask); /* socket stream */ >8 * 標準入力ファイル識別子をファイル識別子集合に加え * socket側のファイル識別子もファイル識別子集合に加えます 8< timeout.tv_sec = 5; timeout.tv_usec = 0; >8 * timeval構造体に,5秒を設定します.入力がなかった場合のタイムアウト時間です. 8< if ((nfound = select (s+1, &readfds, 0, 0, &timeout)) == -1) { perror ("select failed"); } >8 selectの振舞 * 指定時間内にデータがこなければ,nfound の値を0にして,select は終了します. * 指定時間内にデータがくれば, ** データがきた識別子番号を1にして, ** 来ていない識別子番号は0にして, ** nfound の値をデータがきたソケットの個数にする * s+1 は,ファイル識別子集合の個数 * &readfds は,調べるファイル識別子集合を与えて,入力があったファイル識別子集合がセットされて返ってきます. * select は, ** timeout時間内に,指定したファイル識別子集合に入力があった場合,そのファイル識別子集合をreadfds にセットして返します.select の戻り値は,入力のあったファイル識別子の個数です. ** timeout時間内に,入力がなかった場合は,タイムアウトとなり,select の戻り値は0がに返されます. 8< else if (nfound != 0) { if (FD_ISSET(0, &readfds)) { nw = read(0, buf, BUF_LEN); write(s, buf, nw); }; if (FD_ISSET(s, &readfds)) { nw = read(s, buf, BUF_LEN); write(1, buf, nw); } >8 * 0, s のファイル識別子から入力があったかを,FD_ISSETで調べます.