サブルーチンの選択

目的

複数のファイル記述子およびメッセージ・キューの入出力状況を検査します。

ライブラリー

標準 C ライブラリー (libc.a)

構文

#include <sys/time.h>
#include <sys/select.h>
#include <sys/types.h>
int select (Nfdsmsgs, ReadList, WriteList, ExceptList, TimeOut)
int  Nfdsmsgs;
struct sellist * ReadList, *WriteList, *ExceptList;
struct timeval * TimeOut;

説明

select サブルーチンは、指定されたファイル・ディスクリプターとメッセージ・キューを検査して、それらが読み取り (受信) または書き込み (送信) の準備ができているかどうか、あるいは例外条件が保留になっているかどうかを調べます。

接続されていないストリーム・ソケットを選択する場合は、接続が行われたときに戻ります。 接続されたストリーム・ソケットで選択した場合、作動可能メッセージは、データを送受信できることを示します。 通常ファイルのファイル記述子は、読み取り、書き込み、および例外条件に対して常に true を選択します。 For more information on sockets, refer to "Understanding Socket Connections" and the related "Checking for Pending Connections Example Program" dealing with pending connections in AIX® Version 6.1 Communications Programming Concepts.

select サブルーチンは、このオペレーティング・システムの以前のリリースおよび BSD システムとの互換性のためにもサポートされています。

共用メモリー記述子では、 select サブルーチンは true を戻します。

注: 読み取りイベントと書き込みイベントの両方に対して非ブロッキング・ソケットを選択し、宛先ホストに到達できない場合、タイミングの制約のために select が別の動作を示す可能性があります。 詳しくは、本書の「 」セクションを参照してください。

パラメーター

項目 説明
Nfdsmsgs (Nfdsmsgs) 検査するファイル記述子の数とメッセージ・キューの数を指定します。 下位 16 ビットは、検査するファイル記述子を指定するビット・マスクの長さを指定します。上位 16 ビットは、メッセージ・キュー ID を含む配列のサイズを指定します。 Nfdsmsgs パラメーターの半分が 0 の値に等しい場合、対応するビット・マスクまたは配列は存在しないと想定されます。
TimeOut 少なくとも 1 つの選択基準が満たされるのを待機する最大時間を指定する、NULL ポインターまたは timeval 構造体へのポインターのいずれかを指定します。 timeval 構造体は、 /usr/include/sys/time.h ファイルに定義され、以下のメンバーを含んでいます。
struct timeval {
   int tv_sec;        /* seconds       */
   int tv_usec;       /* microseconds  */
    };

TimeOutに指定されているマイクロ秒数。tv_usecプロセスに root ユーザー権限がなく、値が 1 ミリ秒未満の場合は、0 から 999999 までの値が 1 ミリ秒に設定されます。

TimeOut パラメーターが NULL ポインターの場合、 select サブルーチンは、少なくとも 1 つの選択基準が満たされるまで無期限に待機します。 TimeOut パラメーターがゼロを含む timeval 構造体を指している場合、ファイルおよびメッセージ・キューの状況がポーリングされ、 select サブルーチンは即時に戻ります。

ReadListWriteListExceptList 読み取り、書き込み、および例外についてそれぞれ何を検査するかを指定します。 これらを一緒に使用して、選択基準を指定します。 これらの各パラメーターは、ファイル記述子とメッセージ・キューの両方を指定できる sellist 構造体を指します。 プログラムは、以下の形式で sellist 構造体を定義する必要があります。
struct sellist
{
ulong fdsmask[F];        /* file descriptor bit mask  */
int msgids[M];         /* message queue identifiers */
};

このfdsmask配列は、各ビットがファイル記述子に対応するビット・ストリングとして扱われます。 ファイル記述子 n は、ビット(1 < < で表されます。 配列エレメント内の (n mod bits)) fdsmask[n /BITS (int)]。 ( BITS マクロは、 values.h ファイルに定義されています。) 1 に設定される各ビットは、対応するファイル記述子の状況が検査されることを示します。

注: Nfdsmsgs パラメーターの下位 16 ビットは、エレメントではなく ビット の数を指定します。fdsmaskファイル記述子マスクを構成する配列。 最後の int の一部のみがマスクに含まれている場合は、適切な数の下位ビットが使用され、残りの上位ビットは無視されます。 Nfdsmsgs パラメーターの下位 16 ビットを 0 に設定した場合は、以下を定義 しないでくださいfdsmask sellist 構造体内の配列。

次の各整数msgidsarray は、状況を検査するメッセージ・キュー ID を指定します。 値が-11の要素は無視される。 Nfdsmsgs パラメーターの上位 16 ビットは、以下の要素の数を指定します。msgidsarray. Nfdsmsgs パラメーターの高位 16 ビットを 0 に設定した場合は、以下を定義 してはなりませんmsgids sellist 構造体内の配列。

セリスト 注:パラメーター'リードリスト、'書き込みリスト ExceptListで指定される配列は同じサイズである。 ただし、それぞれに同じ数のファイル記述子またはメッセージ・キューを指定する必要はありません。 関心のないファイル記述子ビットを 0 に設定し、以下の追加エレメントを設定します。msgids配列を-1する。

sys/select.h ファイルに定義されている SELLIST マクロを使用して、 sellist 構造体を定義することができます。 このマクロの形式は次のとおりです。

SELLIST(f, m) declarator . . . ;

ここで、 f は、以下のサイズを指定します。fdsmaskm は、配列のサイズを指定します。msgids配列、および各 宣言子 は、この型を持つものとして宣言される変数の名前です。

戻り値

正常終了すると、 select サブルーチンは、選択基準を満たすファイル記述子とメッセージ・キューの総数を示す値を戻します。 このfdsmaskビット・マスクは、1 に設定されたビットが基準を満たすファイル記述子を示すように変更されます。 このmsgids配列が変更され、条件を満たさないメッセージキュー識別子は-1の値に置き換えられる。

戻り値は、下位 16 ビットがファイル記述子の数を示し、上位 16 ビットがメッセージ・キュー ID の数を示すという点で、 Nfdsmsgs パラメーターと似ています。 これらの値は、読み取り、書き込み、および例外のそれぞれの基準を満たす合計値を示します。 したがって、同じファイル記述子またはメッセージ・キューを最大 3 回までカウントすることができます。 sys/select.h ファイルにある NFDS および NMSGS マクロを使用して、これらの 2 つの値を戻り値から分離することができます。 例えば、 rcselect サブルーチンから戻された値が入っている場合、 NFDS(rc) は選択されたファイルの数です。 NMSGS(rc) は、選択されたメッセージ・キューの数です。

TimeOut パラメーターで指定した制限時間が経過すると、 select サブルーチンは値 0 を戻します。

Readlist パラメーターで接続ベースのソケットが指定され、接続が切断されると、 select サブルーチンは正常に戻ります。 しかし、ソケット上の recv サブルーチンは、ソケット接続がクローズされたことを示す値 0 を戻します。

非 BLOKING 接続ベースのソケットの場合、接続が成功した場合も失敗した場合も、 select サブルーチンはエラーなしで正常に戻ります。

接続が正常に完了すると、ソケットは書き込み可能になり、接続でエラーが発生すると、ソケットは読み取り可能と書き込み可能になります。

select サブルーチンを使用する場合、ソケット上の保留エラーを検査することはできません。 保留中のエラーを検査するには、 SOL_SOCKET および SOL_ERROR を指定して getsockopt サブルーチンを呼び出す必要があります。

selectサブルーチンが失敗した場合、-1が返され、エラーを示すグローバル変数errnoがセットされる。 この場合、 ReadListWriteListExceptListパラメータが指す構造体の内容は予測不可能である。

エラー・コード

以下のいずれかが該当する場合、 select サブルーチンは失敗します。

項目 説明
EBADF 無効なファイル記述子またはメッセージ・キュー ID が指定されました。
EAGAIN 内部データ構造の割り振りが失敗しました。
EINTR select サブルーチンの実行中にシグナルがキャッチされ、サブルーチンが再始動されないことを示すシグナル・ハンドラーがインストールされました。
EINVAL TimeOut パラメーターまたは Nfdsmsgs パラメーターに無効な値が指定されました。
EINVAL ファイル記述子の 1 つによって参照される STREAM またはマルチプレクサーは、マルチプレクサーからダウンストリームに (直接または間接に) リンクされます。
EFAULT ReadListWriteListExceptList、またはTimeOutパラメータは、プロセスのアドレス空間外の場所を指す。

以下は、到達不能なホストに接続しようとしたときに、 select サブルーチンが非ブロッキング・ソケットで呼び出された場合の動作の例です。
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <sys/time.h>
#include <errno.h>
#include <stdio.h>

int main()
{
    int sockfd, cnt, i = 1;
    struct sockaddr_in  serv_addr;

    bzero((char *)&serv_addr, sizeof (serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("172.16.55.25");
    serv_addr.sin_port = htons(102);

    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        exit(1);
    if (fcntl(sockfd, F_SETFL, FNONBLOCK) < 0)
        exit(1);
    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof
            (serv_addr)) < 0 && errno != EINPROGRESS)
        exit(1);
    for (cnt=0; cnt<2; cnt++) {
        fd_set  readfds, writefds;

        FD_ZERO(&readfds);
        FD_SET(sockfd, &readfds);
        FD_ZERO(&writefds);
        FD_SET(sockfd, &writefds);

        if (select(sockfd + 1, &readfds, &writefds, NULL,
                NULL) < 0)
            exit(1);
        printf("Iteration %d ==============\n", i);
        printf("FD_ISSET(sockfd, &readfds) == %d\n",
            FD_ISSET(sockfd, &readfds));
        printf("FD_ISSET(sockfd, &writefds) == %d\n",
            FD_ISSET(sockfd, &writefds));
        i++;
    }
    return 0;
}
上記のプログラムの出力を以下に示します。
Iteration 1 ==============
FD_ISSET(sockfd, &readfds) == 0
FD_ISSET(sockfd, &writefds) == 1
Iteration 2 ==============
FD_ISSET(sockfd, &readfds) == 1
FD_ISSET(sockfd, &writefds) == 1

最初の反復では、 select は書き込みイベントのみに通知します。 2 回目の反復では、 select は読み取りイベントと書き込みイベントの両方に通知します。

ノート

FD_SETSIZE は、さまざまな FD マクロが使用するファイル記述子の数を定義する #define 変数です。 FD_SETSIZE のデフォルト値は 65534 のオープン・ファイル記述子です。 この値は、 OPEN_MAXより大きい値に設定することはできません。

詳しくは、 /usr/include/sys/time.h ファイルを参照してください。

ユーザーは、システム・ヘッダー・ファイルを組み込む前に、 FD_SETSIZE をオーバーライドしてより小さい値を選択することができます。 これは、 FD_ZERO のオーバーヘッドがゼロの 65534 ビットになるため、パフォーマンス上の理由から望ましいことです。

パフォーマンスの問題と推奨されるコーディング手法

select サブルーチンは、使用されるオープン・ファイル記述子の数と使用されるビットマップの長さに応じて、非常に計算主体のシステム・コールになります。 多くのテキスト・ブックに示されている例に従わないでください。 サポートされているオープン・ファイルの数が少ないため、ビットマップが不足している場合がほとんどです。 以下を避ける必要があります (ここで、 select は、処理する FD の数として FD_SETSIZE を渡されます)。
select(FD_SETSIZE, ....)

プログラムが FD_ZERO とデフォルトの FD_SETSIZEを使用すると、パフォーマンスが低下します。 FD_ZERO は、どのループにおいても、また各 select 呼び出しの前にも使用してはなりません。 ただし、ビット・ストリングをゼロに 1 回使用しても、問題は発生しません。 この単純なプログラミング方式を使用する予定の場合は、 FD_SETSIZE をオーバーライドして、定義する FD の数を減らす必要があります。 例えば、選択する予定の 2 つの FD のみをプロセスが開く場合に、そのプロセスで数百を超える FD が開かれることがないようにするには、 FD_SETSIZE を約 1024 に下げる必要があります。

selectの最初のパラメーターとして FD_SETSIZE を渡さないでください。 これは、システムが検査する必要があるファイル記述子の最大数を指定します。 プログラムは、割り当てられた最高位の FD を追跡するか、 getdtablesize サブルーチンを使用してこの値を判別する必要があります。 これにより、過度に長いビットマップをカーネルに渡したりカーネルから渡したりする手間を省くことができ、 select が検査する必要がある FD の数を減らすことができます。

selectの代わりに poll システム・コールを使用してください。 poll システム・コールは、 selectと同じ機能を持っていますが、ビットマップの代わりに FD のリストを使用します。 したがって、単一の FD のみを選択する場合は、1 つの FD のみを pollに渡します。 selectを使用する場合は、その FD に割り当てられた FD 番号と同じ長さのビットマップを渡す必要があります。 例えば、 AIX が FD 4000 を割り当てた場合、ビットマップ 4001 ビットの長さを渡す必要があります。