Este artículo necesita citas adicionales para su verificación . ( marzo de 2020 ) |
select es una llamada del sistema y una interfaz de programación de aplicaciones (API) ensistemas operativos similares a Unix y compatibles con POSIX para examinar el estado de los descriptores de archivos de canales de entrada/salida abiertos. [1] La llamada del sistema select es similar a la función poll introducida en UNIX System V y sistemas operativos posteriores. Sin embargo, con el problema c10k , tanto select como poll han sido reemplazados por funciones como kqueue , epoll , /dev/poll y puertos de finalización de E/S . [2]
Un uso común de select fuera de su uso indicado de esperar en los manejadores de archivos es implementar un modo de suspensión portátil de menos de un segundo . Esto se puede lograr pasando NULL para los tres argumentos de fd_set y la duración del modo de suspensión deseado como argumento de tiempo de espera.
En el lenguaje de programación C , la llamada al sistema select se declara en el archivo de encabezado sys/select.h o unistd.h , y tiene la siguiente sintaxis:
int seleccionar ( int nfds , fd_set * readfds , fd_set * writefds , fd_set * errorfds , struct timeval * timeout );
argumento | descripción |
---|---|
nfds | Este es un entero mayor que el máximo de cualquier descriptor de archivo en cualquiera de los conjuntos. En otras palabras, al agregar descriptores de archivo a cada uno de los conjuntos, debe calcular el valor entero máximo de todos ellos, luego incrementar este valor en uno y luego pasarlo como nfds. |
leerfds | Tipo fd_set que contiene los descriptores de archivos que se deben verificar para comprobar si están listos para leer y, en la salida, indica qué descriptores de archivos están listos para leer. Puede ser NULL . |
escriturafds | Tipo fd_set que contiene los descriptores de archivos que se deben verificar para comprobar si están listos para escribir y, en la salida, indica qué descriptores de archivos están listos para escribir. Puede ser NULL . |
errorfds | fd_set tipo que contiene los descriptores de archivo que se deben verificar para detectar condiciones de error pendientes y, en la salida, indica qué descriptores de archivo tienen condiciones de error pendientes. Puede ser NULL . |
se acabó el tiempo | estructura de tipo struct timeval que especifica un intervalo máximo de espera para que se complete la selección. Si el argumento timeout apunta a un objeto de tipo struct timeval cuyos miembros son 0, select() no se bloquea. Si el argumento timeout es NULL, select() se bloquea hasta que un evento haga que una de las máscaras se devuelva con un valor válido (distinto de cero). Linux actualizará el timeout en su lugar para indicar cuánto tiempo ha transcurrido, aunque este comportamiento no es compartido por la mayoría de los demás sistemas Unix. |
fd_set type
Los argumentos se pueden manipular con cuatro macros de utilidad: FD_SET(), FD_CLR(), FD_ZERO() y FD_ISSET() .
Select devuelve el número total de bits establecidos en readfds, writefds y errorfds , o cero si expiró el tiempo de espera y -1 en caso de error.
Los conjuntos de descriptores de archivos que se utilizan en select tienen un tamaño finito, según el sistema operativo. La nueva llamada al sistema poll ofrece una solución más flexible.
#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> #define PUERTO "9421"/* prototipos de funciones */ void die ( const char * ); int principal ( int argc , char ** argv ) { int sockfd , nuevo , maxfd , on = 1 , nready , i ; struct addrinfo * res0 , * res , sugerencias ; búfer de caracteres [ BUFSIZ ]; fd_set maestro , readfds ; int error ; tamaño_t nbytes ; ( void ) memset ( & sugerencias , '\0' , sizeof ( struct addrinfo )); sugerencias . ai_family = AF_INET ; sugerencias . ai_socktype = SOCK_STREAM ; sugerencias . ai_protocol = IPPROTO_TCP ; sugerencias . ai_flags = AI_PASSIVE ; si ( 0 != ( error = getaddrinfo ( NULL , PUERTO , & sugerencias , & res0 ))) errx ( ERROR_DE_SALIDA , "%s" , gai_strerror ( error )); for ( res = res0 ; res ; res = res -> ai_next ) { if ( -1 == ( sockfd = socket ( res -> ai_family , res -> ai_socktype , res -> ai_protocol ))) { perror ( "socket( )" ); continuar ; } si ( -1 == ( setsockopt ( sockfd , SOL_SOCKET , SO_REUSEADDR , ( char * ) & on , sizeof ( int )))) { perror ( "setsockopt()" ); continuar ; } si ( -1 == ( enlazar ( sockfd , res -> ai_addr , res -> ai_addrlen ))) { perror ( "bind()" ); continuar ; } romper ; } si ( -1 == sockfd ) salir ( EXIT_FAILURE ); freeaddrinfo ( res0 ); si ( -1 == ( escuchar ( sockfd , 32 ))) morir ( "escuchar()" ); si ( -1 == ( fcntl ( sockfd , F_SETFD , O_NONBLOCK ))) morir ( "fcntl()" ); FD_ZERO ( & maestro ); FD_ZERO ( & readfds ); FD_SET ( sockfd , y maestro ); maxfd = calcetín ; mientras ( 1 ) { memcpy ( & readfds , & master , sizeof ( master )); ( void ) printf ( "ejecutando select() \n " ); si ( -1 == ( nready = seleccionar ( maxfd + 1 , & readfds , NULL , NULL , NULL ))) morir ( "seleccionar()" ); ( void ) printf ( "Número de descriptores listos: %d \n " , nready ); para ( i = 0 ; i <= maxfd && nready > 0 ; i ++ ) { si ( FD_ISSET ( i , & readfds )) { nready -- ; if ( i == sockfd ) { ( void ) printf ( "Intentando aceptar() nuevas conexiones \n " ); si ( -1 == ( nuevo = aceptar ( sockfd , NULL , NULL ))) { si ( EWOULDBLOCK != errno ) morir ( "aceptar()" ); romper ; } demás { si ( -1 == ( fcntl ( nuevo , F_SETFD , O_NONBLOCK ))) morir ( "fcntl()" ); FD_SET ( nuevo , & maestro ); si ( maxfd < nuevo ) maxfd = nuevo ; } } else { ( void ) printf ( "recv() datos de uno de los descriptores \n " ); nbytes = recv ( i , buffer , sizeof ( buffer ), 0 ); si ( nbytes <= 0 ) { si ( EWOULDBLOCK != errno ) morir ( "recv()" ); romper ; } buffer [ nbytes ] = '\0' ; printf ( "%s" , buffer ); ( void ) printf ( "%zi bytes recibidos. \n " , nbytes ); cerrar ( i ); FD_CLR ( i , & master ); } } } } devuelve 0 ; } void die ( const char * msg ) { perror ( msg ); salir ( FALLO_SALIDA ); }