selectはUnix 系およびPOSIX準拠のオペレーティングシステムにおけるシステムコールおよびアプリケーションプログラミングインターフェース(API) であり、開いている入出力チャネルのファイル記述子の状態を調べるために使用されます。 [1] select システムコールはUNIX System V 以降のオペレーティングシステムで導入されたpoll機能に似ています。ただし、 c10k 問題により、 select と poll はいずれもkqueue、 epoll、 /dev/poll 、 I/O 完了ポートなどに置き換えられました。 [2]
ファイルハンドルを待機するという明示的な用途以外での select の一般的な使用法の 1 つは、移植可能な 1 秒未満のスリープを実装することです。これは、3 つの fd_set 引数すべてに NULL を渡し、必要なスリープの期間をタイムアウト引数として渡すことで実現できます。
C プログラミング言語では、select システム コールはヘッダー ファイル sys/select.h またはunistd.hで宣言されており、構文は次のとおりです。
int select ( int nfds 、fd_set * readfds 、fd_set * writefds 、fd_set * errorfds 、struct timeval * timeout );
fd_set type引数は、 FD_SET()、FD_CLR()、FD_ZERO()、FD_ISSET()の 4 つのユーティリティ マクロを使用して操作できます。
Select は、 readfds、writefds、errorfdsに設定されているビットの合計数を返します。タイムアウトが経過した場合は 0 を返し、エラーの場合は -1 を返します。
select で使用されるファイル記述子のセットのサイズは、オペレーティング システムに応じて有限です。新しいシステム コールpoll は、より柔軟なソリューションを提供します。
例
#include <stdio.h> #include <stdlib.h> #include <string.h>
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h>
#include <sys/select.h> #include <fcntl.h> #include <unistd.h> #include <err.h> #include <errno.h>
#ポート「9421」を定義します
/* 関数プロトタイプ */
void die ( const char * );
int main ( int argc 、char ** argv ) { int sockfd 、new 、maxfd 、on = 1 、nready 、i ;
構造体addrinfo * res0 、* res 、ヒント;
charバッファ[ BUFSIZ ];
fd_setマスター、readfds ;
整数エラー;
ssize_t nバイト;
( void ) memset ( & hints , '\0' , sizeof ( struct addrinfo ));
ヒント. ai_family = AF_INET ;ヒント. ai_socktype = SOCK_STREAM ;ヒント. ai_protocol = IPPROTO_TCP ;ヒント. ai_flags = AI_PASSIVE ;
if ( 0 != ( error = getaddrinfo ( NULL 、PORT 、& hints 、& res0 ))) errx ( EXIT_FAILURE 、"%s" 、gai_strerror ( error ));
for ( res = res0 ; res ; res = res -> ai_next ) { if ( -1 == ( sockfd =ソケット( res -> ai_family , res -> ai_socktype , res -> ai_protocol ))) { perror ( "socket( )" );続く; }
if ( -1 == ( setsockopt ( sockfd 、SOL_SOCKET 、SO_REUSEADDR 、( char * ) & on 、sizeof ( int )))) { perror ( "setsockopt()" );続行; }
if ( -1 == ( bind ( sockfd 、res -> ai_addr 、res -> ai_addrlen ))) { perror ( "bind()" );続行; }
壊す;
}
( -1 == sockfd )の場合、終了( EXIT_FAILURE );
フリーアドレス情報( res0 );
if ( -1 == ( listen ( sockfd 、32 ))) die ( "listen()" );
if ( -1 == ( fcntl ( sockfd 、F_SETFD 、O_NONBLOCK ))) die ( "fcntl()" );
FD_ZERO ( & master );
FD_ZERO ( & readfds );
FD_SET ( sockfd 、&マスター);
最大fd = sockfd ;
while ( 1 ) { memcpy ( & readfds , & master , sizeof ( master ));
( void ) printf ( "select() を実行中\n " );
if ( -1 == ( nready = select ( maxfd + 1 , & readfds , NULL , NULL , NULL ))) die ( "select()" );
( void ) printf ( "準備完了記述子の数: %d \n " , nready );
for ( i = 0 ; i <= maxfd && nready > 0 ; i ++ ) { if ( FD_ISSET ( i , & readfds )) { nready -- ;
if ( i == sockfd ) { ( void ) printf ( "新しい接続を accept() しようとしています\n " );
if ( -1 == ( new = accept ( sockfd , NULL , NULL ))) { if ( EWOULDBLOCK != errno ) die ( "accept()" );
壊す;
}
それ以外
{
if ( -1 == ( fcntl ( new 、F_SETFD 、O_NONBLOCK ))) die ( "fcntl()" );
FD_SET (新規、&マスター);
maxfdがnewの場合、maxfd はnewになります。
else
{ ( void ) printf ( "記述子の1つからrecv()データを取得\n " );
nbytes = recv ( i 、buffer 、sizeof ( buffer )、0 ); if ( nbytes <= 0 ) { if ( EWOULDBLOCK != errno ) die ( "recv()" );
壊す;
}
buffer [ nbytes ] = '\0' ; printf ( "%s" , buffer );
( void ) printf ( "%zi バイトを受信しました。\n " , nbytes );
閉じる( i );
FD_CLR ( i 、&マスター);
}
}
}
}
0を返します。}
void die ( const char * msg ) { perror ( msg ); exit ( EXIT_FAILURE ); }
参照
参考文献
- ^ Computer Systems Research Group (1994)。「select、pselect — 同期 I/O 多重化」。BSD相互参照。NetBSD 。
- ^ 「接続処理方法」. nginx .org .
外部リンク
- – システム インターフェース リファレンス、The Single UNIX 仕様、バージョン 4、The Open Group
- FreeBSD、NetBSD、OpenBSD、DragonFly BSD の select(2) のマニュアルページ
