ネットワークインタフェース

入出力の多重化

要求は、複数のソケットまたはファイルの間で多重化できます。このためには select(3C) を使用します。

#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
 ...
fd_set readmask, writemask, exceptmask;
struct timeval timeout;
 ...
select(nfds, &readmask, &writemask, &exceptmask, &timeout);

select(3C) の最初の引数は、続く 3 つの引数によって示されるリスト内のファイル記述子の数です。

select(3C) の 2 つ目、3 つ目、4 つ目の引数は、3 つのファイル記述子セット (読み取りを行う記述子セット、書き込みを行うセット、および例外条件が認められるセット) を指します。帯域外データは、唯一の例外条件です。これらのポインタはどれも、適切にキャストされた NULL です。各セットは、ロング整数ビットマスクの配列を含む構造体です。配列のサイズは、FD_SETSIZE (select.h で定義されている) で設定します。配列には、各 FD_SETSIZE ファイル記述子のための 1 ビットを保持するだけの長さがあります。

マクロ FD_SET(fd, &mask) はセット mask 内のファイル記述子 fd を追加し、マクロ FD_CLR(fd, &mask) はこの記述子を削除します。セット mask は、使用前にゼロにする必要があります。マクロ FD_ZERO(&mask) は、セット mask を消去します。

select(3C) の 5 つ目の引数によって、タイムアウト値を指定できます。timeout ポインタが NULL の場合、select(3C) は、記述子が選択できるようになるか、あるいはシグナルが受信されるまでブロックします。timeout 内のフィールドが 0 に設定されると、select(3C) はただちにポーリングして戻ります。

select(3C) は、通常、選択されたファイル記述子の数を返します。select(3C) は、タイムアウトの期限が過ぎると 0 を返します。select(3C) は、ファイル記述子マスクが変更されず、エラーまたは割り込みが発生した場合、そこで指定されたエラー番号 errno に対し -1 を返します。成功した場合に返される 3 つのセットは読み取り可能なファイル記述子、書き込み可能なファイル記述子、または例外条件が保留されたファイル記述子を示します。

FD_ISSET(fd, &mask) マクロを使用して、選択マスク内のファイル記述子のステータスをテストしてください。セット mask 内に fd が存在する場合はゼロ以外の値が返され、存在しない場合は 0 が返されます。読み取りセットで FD_ISSET(fd, &mask) マクロの前に select(3C) を使用して、待ち行列に入っている、ソケット上の接続要求を確認します。

例 2-5 は、accept(3SOCKET) 呼び出しによって新しい接続をピックアップするタイミングを決定するために、読み取り用の「リスニング (待機) 」ソケットで select を使用する方法を示しています。このプログラムは、接続要求を受け入れ、データを読み取り、単一のソケットで切断します。


例 2-5 select(3C) を使用して保留状態の接続を確認する

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
 
#define TRUE 1
 
/*
 * このプログラムは、accept を呼び出す前に、select を使用
 * して、他のだれかが接続を試みていないかチェックします。
 */
 
main()
{
   int sock, length;
   struct sockaddr_in6 server;
   int msgsock;
   char buf[1024];
   int rval;
   fd_set ready;
   struct timeval to;
 
   /* ソケットを開き、そのソケットを先の例と同様にバインドする。*/
 
   /* 接続の受け入れを開始する。*/
   listen(sock, 5);
   do {
      FD_ZERO(&ready);
      FD_SET(sock, &ready);
      to.tv_sec = 5;
      to.tv_usec = 0;
      if (select(sock + 1, &ready, (fd_set *)0, (fd_set *)0, &to) == -1) {
         perror("select");
         continue;
      }
      if (FD_ISSET(sock, &ready)) {
         msgsock = accept(sock, (struct sockaddr *)0,
            (int *)0);
         if (msgsock == -1)
            perror("accept");
         else do {
            memset(buf, 0, sizeof buf);
            if ((rval = read(msgsock, buf, 1024)) == -1)
               perror("reading stream message");
            else if (rval == 0)
               printf("Ending connection¥n");
            else
               printf("-->%s¥n", buf);
         } while (rval > 0);
         close(msgsock);
      } else
         printf("Do something else¥n");
   } while (TRUE);
	   exit(0);
}

以前のバージョンの select(3C) ルーチンでは、引数は fd_sets のポインタではなく、整数のポインタでした。ファイル記述子の数が整数内のビット数よりも小さい場合は、現在でもこのような呼び出しを使用できます。

select(3C) は、同期多重スキーマを提供します。SIGIOSIGURG シグナル (「拡張機能」を参照) は、出力の完了、入力の有効性、および例外条件の非同期通知を提供します。