Modelo Cliente-Servidor y Multiplexión de I/O (select)
Clasificación de Servidores
    Servidor Iterativo
  1. Espera por la llegada de un cliente
  2. Procesa el requerimiento de un cliente
  3. Envía la respuesta al cliente que envió el requerimiento
  4. Regresa al primer paso
Éste es el caso típico de servidores UDP (UDPServer.c   UDPClient.c).

    Servidor Concurrente

  1. Espera por la llegada de un cliente
  2. Inicia un servidor para manejar los requerimientos del cliente. Ésto involucra la creación de un nuevo proceso o hilo. Cuando el cliente se va (termina) el proceso o hilo también termina.
  3. Regresa al primer paso.
Éste es el caso típico de servidores TCP (TCPServer.c   TCPClient.c).

Destacar:

  1. Valores de puertas asignadas cuando se establece una conexión.
  2. Llamados para obtener información sobre la conexión: gethostname(), gethostbyname(), inet_ntoa(), inet_addr(), getsockname(), getpeername(), setsockopt().
  3. Configuración de puerta como reusable.
Una situación intermedia es creada cuando un servidor TCP atiende múltiples clientes en forma secuencial por requerimiento. En este caso tenemos:
  1. Espera por la llegada de un cliente o nuevo requerimiento de un cliente ya conectado.
  2. Acepta la conexión de un nuevo cliente o procesa requerimiento de uno ya conectado
  3. Si se atendió un requerimiento, envía la respuesta al cliente que envió el requerimiento
  4. Regresa al primer paso
Para poder esperar requerimientos que pueden llegar por múltiples descriptores, se dispone de la función select().
Algunas otras técnicas que se parecen a select pero no siempre son las más adecuadas son:
  1. Creación de múltiples procesos y cada uno atiende cada descriptor (Se deben eliminar carreras críticas),
  2. El uso de hilos en el caso anterior a cambio de procesos,
  3. Uso de I/O sin bloqueo (nonbloking I/O),
  4. Uso de I/O asíncrono. Se anuncia deseo de hacer I/O y el proceso es interrunpido cuando tiene algo.


Las funciones select y poll proveen un mecanismo para que los programas chequeen un grupo de descriptores y sepan cuando existe entradas, salidas, o alguna condición de excepción en alguno de ellos.

#include <sys/types.h>
#include <sys/time.h>

int select ( int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval * timeout_ptr );

void FD_SET ( int fd, fd_set * fdset);
void FD_CLR ( int fd, fd_set * fdset);
void FD_ISSET ( int fd, fd_set * fdset);
void FD_ZERO ( fd_set * fdset);

struct timeval {
    long tv_sec;    /* segundos*/
    long tv_usec;    /* micro segundos */
}
 

Valores para timeout_ptr
  1. NULL : Espera por siempre. Espera infinita por actividad en alguno de los descriptores. Esta espera puede ser interrumpida por una señal.
  2. tv_sec = tv_usec = 0:    No espera. Todos los descriptores son chequeados y se retorna inmediatamente.
  3. tv_sec != 0 ó tv_usec != 0 : Se espera hasta el tiempo indicado. Si hay actividad antes, se retorna inmediatamente, sino se retorna como el caso anterior al término del timeout.
Valores retornado por select:


Ejemplos

  1. Leyendo entradas de múltiples terminales (o ventanas xterm o telnet) select
  2. Como el caso de la tarea Servidor Iterativo Cliente