/* * Javier Abellán. 14 de Abril de 2003 * * Ejemplo de como un servidor puede manejar varios clientes con select(). * Este programa hace de servidor. */ #include #include #include #include #include #define MAX_CLIENTES 10 /* Prototipos de las funciones definidas en este fichero */ void nuevoCliente (int servidor, int *clientes, int *nClientes); int dameMaximo (int *tabla, int n); void compactaClaves (int *tabla, int *n); /* * Programa principal. * Crea un socket servidor y se mete en un select() a la espera de clientes. * Cuando un cliente se conecta, le atiende y lo añade al select() y vuelta * a empezar. */ main() { int socketServidor; /* Descriptor del socket servidor */ int socketCliente[MAX_CLIENTES];/* Descriptores de sockets con clientes */ int numeroClientes = 0; /* Número clientes conectados */ fd_set descriptoresLectura; /* Descriptores de interes para select() */ int buffer; /* Buffer para leer de los socket */ int maximo; /* Número de descriptor más grande */ int i; /* Para bubles */ /* Se abre el socket servidor, avisando por pantalla y saliendo si hay * algún problema */ socketServidor = Abre_Socket_Inet ("cpp_java"); if (socketServidor == -1) { perror ("Error al abrir servidor"); exit (-1); } /* Bucle infinito. * Se atiende a si hay más clientes para conectar y a los mensajes enviados * por los clientes ya conectados */ while (1) { /* Cuando un cliente cierre la conexión, se pondrá un -1 en su descriptor * de socket dentro del array socketCliente. La función compactaClaves() * eliminará dichos -1 de la tabla, haciéndola más pequeña. * * Se eliminan todos los clientes que hayan cerrado la conexión */ compactaClaves (socketCliente, &numeroClientes); /* Se inicializa descriptoresLectura */ FD_ZERO (&descriptoresLectura); /* Se añade para select() el socket servidor */ FD_SET (socketServidor, &descriptoresLectura); /* Se añaden para select() los sockets con los clientes ya conectados */ for (i=0; i 0)) printf ("Cliente %d envía %d\n", i+1, buffer); else { /* Se indica que el cliente ha cerrado la conexión y se * marca con -1 el descriptor para que compactaClaves() lo * elimine */ printf ("Cliente %d ha cerrado la conexión\n", i+1); socketCliente[i] = -1; } } } /* Se comprueba si algún cliente nuevo desea conectarse y se le * admite */ if (FD_ISSET (socketServidor, &descriptoresLectura)) nuevoCliente (socketServidor, socketCliente, &numeroClientes); } } /* * Crea un nuevo socket cliente. * Se le pasa el socket servidor y el array de clientes, con el número de * clientes ya conectados. */ void nuevoCliente (int servidor, int *clientes, int *nClientes) { /* Acepta la conexión con el cliente, guardándola en el array */ clientes[*nClientes] = Acepta_Conexion_Cliente (servidor); (*nClientes)++; /* Si se ha superado el maximo de clientes, se cierra la conexión, * se deja todo como estaba y se vuelve. */ if ((*nClientes) >= MAX_CLIENTES) { close (clientes[(*nClientes) -1]); (*nClientes)--; return; } /* Envía su número de cliente al cliente */ Escribe_Socket (clientes[(*nClientes)-1], (char *)nClientes, sizeof(int)); /* Escribe en pantalla que ha aceptado al cliente y vuelve */ printf ("Aceptado cliente %d\n", *nClientes); return; } /* * Función que devuelve el valor máximo en la tabla. * Supone que los valores válidos de la tabla son positivos y mayores que 0. * Devuelve 0 si n es 0 o la tabla es NULL */ int dameMaximo (int *tabla, int n) { int i; int max; if ((tabla == NULL) || (n<1)) return 0; max = tabla[0]; for (i=0; i max) max = tabla[i]; return max; } /* * Busca en array todas las posiciones con -1 y las elimina, copiando encima * las posiciones siguientes. * Ejemplo, si la entrada es (3, -1, 2, -1, 4) con *n=5 * a la salida tendremos (3, 2, 4) con *n=3 */ void compactaClaves (int *tabla, int *n) { int i,j; if ((tabla == NULL) || ((*n) == 0)) return; j=0; for (i=0; i<(*n); i++) { if (tabla[i] != -1) { tabla[j] = tabla[i]; j++; } } *n = j; }