select — это системный вызов и интерфейс прикладного программирования (API) в Unix-подобных и POSIX -совместимых операционных системах для проверки состояния файловых дескрипторов открытых каналов ввода/вывода. [1] Системный вызов select похож на функцию poll , представленную в UNIX System V и более поздних операционных системах. Однако с проблемой c10k и select, и poll были заменены такими функциями, как kqueue , epoll , /dev/poll и портами завершения ввода/вывода . [2]
Одним из распространенных вариантов использования select за пределами его заявленного использования для ожидания файловых дескрипторов является реализация переносимого субсекундного sleep . Этого можно добиться, передав NULL для всех трех аргументов fd_set и продолжительность желаемого sleep в качестве аргумента тайм-аута.
В языке программирования 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() .
Select возвращает общее количество битов, установленных в readfds, writefds и errorfds , или ноль, если время ожидания истекло, и -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 ; struct addrinfo * res0 , * res , подсказки ; буфер символов [ BUFSIZ ]; fd_set master , readfds ; ошибка int ; ssize_t nbytes ; ( void ) memset ( & hints , '\0' , sizeof ( struct addrinfo )); подсказки . ai_family = AF_INET ; подсказки . ai_socktype = SOCK_STREAM ; подсказки . ai_protocol = IPPROTO_TCP ; подсказки . ai_flags = AI_PASSIVE ; если ( 0 != ( ошибка = getaddrinfo ( NULL , PORT , & hints , & res0 ))) errx ( EXIT_FAILURE , "%s" , gai_strerror ( ошибка )); for ( res = res0 ; res ; res = res -> ai_next ) { if ( -1 == ( sockfd = сокет ( res -> ai_family , res -> ai_socktype , res -> ai_protocol ))) { perror ( "socket( )" ); продолжать ; } если ( -1 == ( setsockopt ( sockfd , SOL_SOCKET , SO_REUSEADDR , ( char * ) & on , sizeof ( int )))) { perror ( "setsockopt()" ); продолжить ; } если ( -1 == ( bind ( sockfd , res -> ai_addr , res -> ai_addrlen ))) { perror ( "bind()" ); продолжить ; } перерыв ; } если ( -1 == sockfd ) выход ( EXIT_FAILURE ); freeaddrinfo ( res0 ); если ( -1 == ( listen ( sockfd , 32 ))) умереть ( "listen()" ); если ( -1 == ( fcntl ( sockfd , F_SETFD , O_NONBLOCK ))) die ( "fcntl()" ); FD_ZERO ( & master ); FD_ZERO ( & readfds ); FD_SET ( sockfd , & master ); maxfd = sockfd ; while ( 1 ) { memcpy ( & readfds , & master , sizeof ( master )); ( void ) printf ( "выполняется select() \n " ); если ( -1 == ( nready = select ( maxfd + 1 , & readfds , NULL , NULL , NULL ))) die ( "select()" ); ( void ) printf ( "Количество готовых дескрипторов: %d \n " , nready ); для ( i = 0 ; i <= maxfd && nready > 0 ; i ++ ) { если ( FD_ISSET ( i , & readfds )) { nready -- ; if ( i == sockfd ) { ( void ) printf ( "Попытка принять() новое(ие) соединение(я) \n " ); если ( -1 == ( новый = принять ( sockfd , NULL , NULL ))) { если ( EWOULDBLOCK != errno ) умереть ( "принять()" ); перерыв ; } еще { если ( -1 == ( fcntl ( новый , F_SETFD , O_NONBLOCK ))) die ( "fcntl()" ); FD_SET ( новый , & главный ); если ( maxfd < новый ) maxfd = новый ; } } else { ( void ) printf ( "recv() данные из одного из дескрипторов \n " ); nbytes = recv ( i , buffer , sizeof ( buffer ), 0 ); если ( nbytes <= 0 ) { если ( EWOULDBLOCK != errno ) die ( "recv()" ); перерыв ; } буфер [ nbytes ] = '\0' ; printf ( "%s" , буфер ); ( void ) printf ( "получено %zi байт. \n " , nbytes ); закрыть ( i ); FD_CLR ( i , & master ); } } } } вернуть 0 ; } void die ( const char * msg ) { perror ( msg ); выход ( EXIT_FAILURE ); }