ソフトウェア設計及び演習2017

非同期通信とselect

複数の入力を扱う

あるいは,select (システムコール) の使い方

参考にするプログラム

serv.c service関数

service 関数の動き

サーバは,

  • 一人のクライアントからのメッセージを画面に表示
    • ソケット側のファイル識別子を read して,
    • 標準出力のファイル識別子へ write.
  • 自身のキーボードからの入力をクライアントへ送信
    • 標準入力のファイル識別子を read して,
    • ソケット側のファイル識別子へ write.

のどちらかを,行います.ただし,その順番を決めてしまった場合には, 入力データが届いていないファイル識別子を read しても read は待ち状態のままで,入力があるまで動き出しません

待ちを生じさせないためには,入力データがあるかを確かめてから read する必要があります.それを行うのが select システムコールです.

このように入力データの到着順によって入力を行うことを, 非同期入力と呼びます.

service 関数の説明

struct fd_set
  • 複数のファイル識別子の集合を表す構造体です.
struct fd_set mask, readfds;
  • maskは入力を調べるファイル識別子集合
  • readfds は入力データがあったファイル識別子集合
  struct timeval timeout;
  • 待ち合わせ時間設定用構造体
  FD_ZERO(&mask);
  • maskのファイル識別子集合を空にします.
  FD_SET(0, &mask); /* stdin */
  FD_SET(s, &mask); /* socket stream */
  • 標準入力ファイル識別子をファイル識別子集合に加え
  • socket側のファイル識別子もファイル識別子集合に加えます
  timeout.tv_sec  = 5;
  timeout.tv_usec = 0;
  • timeval構造体に,5秒を設定します.入力がなかった場合のタイムアウト時間です.
      if ((nfound = select (s+1, &readfds, 0, 0, &timeout)) == -1) {
        perror ("select failed");
      }

selectの振舞

  • 指定時間内にデータがこなければ,nfound の値を0にして,select は終了します.
  • 指定時間内にデータがくれば,
    • データがきた識別子番号を1にして,
    • 来ていない識別子番号は0にして,
    • nfound の値をデータがきたソケットの個数にする
  • s+1 は,ファイル識別子集合の個数
  • &readfds は,調べるファイル識別子集合を与えて,入力があったファイル識別子集合がセットされて返ってきます.
  • select は,
    • timeout時間内に,指定したファイル識別子集合に入力があった場合,そのファイル識別子集合をreadfds にセットして返します.select の戻り値は,入力のあったファイル識別子の個数です.
    • timeout時間内に,入力がなかった場合は,タイムアウトとなり,select の戻り値は0がに返されます.
      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);
            }
  • 0, s のファイル識別子から入力があったかを,FD_ISSETで調べます.


最終更新日:2017/04/03 09:14:25