選択 (Unix)

selectは、 Unix系およびPOSIX準拠のオペレーティングシステムにおけるシステムコールおよびアプリケーションプログラミングインターフェース(API)であり、開いている入出力チャネルのファイル記述子の状態を調べるために使用されます。 [1] selectシステムコールは、UNIX System V以降のオペレーティングシステムで導入されたpoll機能に似ています。しかし、 c10k問題により、selectとpollはどちらもkqueue epoll、/dev/poll、 I/O完了ポートなどの機能に置き換えられました。 [2]

ファイルハンドルの待機という本来の用途以外で、select の一般的な使用法の一つは、移植性の高い1秒未満のスリープを実装することです。これは、3つの fd_set 引数全てに NULL を渡し、必要なスリープ時間を timeout 引数に渡すことで実現できます。

C プログラミング言語では、select システム コールはヘッダー ファイル sys/select.h またはunistd.hで宣言されており、構文は次のとおりです。

int select ( int nfds fd_set * readfds fd_set * writefds fd_set * errorfds struct timeval * timeout );           
口論説明
nfdsこれは、各セット内のファイル記述子の最大値より1大きい整数です。つまり、各セットにファイル記述子を追加する際には、すべてのセットの最大の整数値を計算し、その値を1ずつ増やして、nfdsとして渡す必要があります。
読み取りファイル読み取り準備ができているかどうかを確認するファイル記述子を保持するfd_set型。出力では、どのファイル記述子が読み取り準備ができているかを示します。 NULLにすることもできます。
writefds書き込み準備ができているかどうかを確認するファイル記述子を保持するfd_set型。出力では、どのファイル記述子が書き込み準備ができているかを示します。 NULLにすることもできます。
exceptfdsfd_set型は、例外条件が保留されているかどうかをチェックするファイル記述子を保持し、出力では、例外条件が保留されているファイル記述子を示します。例外条件の例としては、TCPソケットに帯域外データが存在することが挙げられます。NULL も指定できます
タイムアウト選択が完了するまでの最大待機時間を指定する struct timeval 型の構造体です。timeout 引数が struct timeval 型のオブジェクトを指し、そのメンバーが 0 の場合、select()はブロックしません。timeout 引数がNULLの場合、select() は、イベントによってマスクの1つが有効な値(0以外の値)で返されるまでブロックします。Linux は経過時間を示すためにタイムアウトをその場で更新しますが、この動作は他のほとんどの Unix システムでは共有されていません。

fd_set type引数は、 FD_SET()、FD_CLR()、FD_ZERO()FD_ISSET()の 4 つのユーティリティ マクロを使用して操作できます

Select は、readfds、writefdserrorfdsに設定されているビットの合計数を返します。タイムアウトが経過した場合は 0 を返し、エラーの場合は -1 を返します。

selectで使用されるファイル記述子のセットのサイズは、オペレーティングシステムによって異なりますが有限です。新しいシステムコールpollは、より柔軟なソリューションを提供します。

#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <err.h> #include <fcntl.h> #include <netdb.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/select.h> #include <sys/types.h> #include <unistd.h>            #ポート「9421」を定義するvoid die ( const char * msg ) { perror ( msg ); exit ( EXIT_FAILURE ); }      typedef struct addrinfoアドレス情報;   int main ( int argc , char * argv []) { int sockfd ;        アドレス情報* res0 ;  charバッファ[ BUFSIZ ];  fd_setマスター; fd_set readfds ;    intエラー;  ssize_t nバイト;  memset ( & hints , '\0' , sizeof ( struct addrinfo ));    AddressInfo *ヒント= { . ai_family = AF_INET . ai_socktype = SOCK_STREAM . ai_protocol = IPPROTO_TCP . ai_flags = AI_PASSIVE };                 if ( int error = getaddrinfo ( NULL PORT & hints & res0 )) { errx ( EXIT_FAILURE "%s" gai_strerror ( error )); }             for ( AddressInfo * res = res0 ; res ; res = res -> ai_next )) { if (( sockfd =ソケット( res -> ai_family , res -> ai_socktype , res -> ai_protocol )) == -1 ) { perror ( "socket()" );続く; }                      int on = 1 ; if ( setsockopt ( sockfd SOL_SOCKET SO_REUSEADDR ( char * ) & on sizeof ( int )) == -1 ) { perror ( "setsockopt()" );続行; }                if ( bind ( sockfd res -> ai_addr res -> ai_addrlen ) == -1 ) { perror ( "bind()" );続行; }          壊す; }  sockfd == -1場合{ EXIT_FAILURE を返します; }        フリーアドレス情報( res0 ); if ( listen ( sockfd , 32 ) == -1 ) { die ( "listen()" ); }        if ( fcntl ( sockfd , F_SETFD , O_NONBLOCK ) == -1 ) { die ( "fcntl()" ); }         FD_ZERO ( & master ); FD_ZERO ( & readfds );  FD_SET ( sockfd & master );  int maxfd = sockfd ;    while ( true ) { memcpy ( & readfds & master sizeof ( master ));      printf ( "select() を実行中\n " ); int nready ; if ( nready = select ( maxfd + 1 , & readfds , NULL , NULL , NULL ) == -1 ) { die ( "select()" ); }               printf ( "準備完了記述子の数: %d \n " , nready );  for ( int i = 0 ; i <= maxfd && nready > 0 ; i ++ ) { if ( FD_ISSET ( i , & readfds )) { nready -- ;                   if ( i == sockfd ) { printf ( "新しい接続をaccept()しようとしています\n " );      int newval ; if (( newval = accept ( sockfd , NULL , NULL )) == -1 ) { if ( EWOULDBLOCK != errno ) { die ( "accept()" ); }                  ブレーク; }そうでなければ{    if ( fcntl ( newval , F_SETFD , O_NONBLOCK ) == -1 ) { die ( "fcntl()" ); }         FD_SET ( newval & master );  if ( maxfd < newval ) { maxfd = newval ; } } } else { printf ( "recv() data from one of descriptors(s) \n " );              nbytes = recv ( i , buffer , sizeof ( buffer ), 0 ); if ( nbytes <= 0 ) { if ( EWOULDBLOCK != errno ) { die ( "recv()" ); }                  壊す; }  buffer [ nbytes ] = '\0' ; printf ( "%s" , buffer );     printf ( "%ziバイトを受信しました。\n " , nbytes );  close ( i ); FD_CLR ( i , & master );   } }  } } 0を返す; }  

参照

参考文献

  1. ^ Computer Systems Research Group (1994). 「select, pselect — 同期I/O多重化」. BSD相互参照. NetBSD .
  2. ^ 「接続 処理方法」。nginx.org
  • select – システムインタフェースリファレンス、The Single UNIX 仕様、バージョン5、The Open Group
  • FreeBSD、NetBSD、OpenBSD、DragonFly BSDのselect(2)のマニュアルページ
「https://en.wikipedia.org/w/index.php?title=Select_(Unix)&oldid=1321201095」から取得