プログラミングインタフェース

入出力の多重化

要求は、複数のソケットまたは複数のファイルに多重化できます。多重化を行うには 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 は使用前に 0 にする必要があり、マクロ FD_ZERO (&mask) がセットをクリアします。

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

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

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

次の例は、読み取り用のリスニング (待機) ソケット上で select (3C) を使用することによって、accept(3SOCKET) 呼び出しでいつ新しいコネクションをピックアップできるかどうかタイミングを判定する方法を示します。このプログラムは、コネクション要求を受け入れ、データを読み取り、単一のソケットで切断します。


例 8–4 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
/*
 * This program uses select to check that someone is
 * trying to connect before calling accept.
 */
main() {
    int sock, length;
    struct sockaddr_in6 server;
    int msgsock;
    char buf[1024];
    int rval;
    fd_set ready;
    struct timeval to;
    /* Open a socket and bind it as in previous examples. */
    /* Start accepting connections. */
    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, sizeof(buf))) == -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) ルーチンは同期多重化スキーマを提供します。SIGIO シグナルと SIGURG シグナル (「ソケットの拡張機能」を参照) によって、出力の完了、入力の有効性、および例外条件の非同期通知を指定できます。