CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 1 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes JUNIO 2003 Se desea desarrollar un servidor como el de la práctica 3 de LSC (Chat) pero sobre conexiones fiables. Por ello, deberá ofrecer: Multiplexación E/S para al menos 5 clientes simultáneos (Utilizar obligatoriamente la función select). Las conexiones serán fiables, previamente establecidas. Los mensajes que se pueden transmitir no superarán los 1024 bytes. El servidor se encargará de escuchar todos los clientes al mismo tiempo. A continuación de aquel que “interrumpa”, leerá el paquete, el cual retransmitirá al resto de los clientes. B) Escriba el código del servidor referente a la gestión del socket: apertura y admisión de conexiones de los clientes (30%). C) Escriba el código para conseguir el funcionamiento del servidor para dos clientes (25%). D) Extienda el código para que gestione los 5 clientes (Evitar usar código redundante) (20%). #include <sys/socket.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <unistd.h> #include <sys/select.h> #define LISTENQ 5 // Tamaño de lista de clientes (4 también sería válido) #define MAXCLIENT 5 // Número máximo de clientes #define MSG_SIZE 1024 //Tamaño máximo del mensaje de texto #define SERVER_PORT 3000 int main (int argc, char **argv) { int i, maxi, maxfd, listenfd, connfd, sockfd, nready; int client[MAXCLIENT]; ssize_t n; fd_set rset, allset; char msg[MSG_SIZE]; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"; exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(SERVER_PORT); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 2 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de 5 clientes maxfd=listenfd; maxi=-1; for (i=0; i<MAX_CLIENT;i++) //Inicialización del array de clientes client[i]=-1; FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd,&allset); for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset){ //CLIENTE NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta cli for (i=0; i<MAX_CLIENT; i++) //Actualización del array if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) maxfd=connfd; if (i>maxi) maxi=i; } if (--nready<=0) continue; //Previsión para más de una interrupción /* ESPACIO RESERVADO PARA EL PROCESADO DEL SERVIDOR*/ } //Del bucle principal } //Del main. José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 3 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes C) /* CÓDIGO SERVIDOR PARA DOS CLIENTES*/ i=0; while(i<=maxi && client[i]<0){ i++; } if(i<=maxi) sockfd1=client[i]; j=i; while(j<=maxi && client[j]<0){ j++; } if(j<=maxi) sockfd2=client[j]; if (FD_ISSET(sockfd1, &rset)) if ((n=read(sockfd1, msg,1024))==0){ //Para el caso de FIN del primero de ellos close(sockfd1); FD_CLR(sockfd1,&allset); client[i]=-1; } else write (sockfd2, msg, 1024); //Se transmite al segundo cliente if (FD_ISSET(sockfd2, &rset)) if ((n=read(sockfd2, msg,1024))==0){ //Para el caso de FIN del segundo close(sockfd1); FD_CLR(sockfd2,&allset); client[j]=-1; } else write (sockfd1, msg, 1024); //Se transmite al primero D) /*Código para n=5 clientes*/ for (i=0; i<=maxi; i++){ if ((sockfd1 =client[i])<0) // Se van a comprobar todos los clientes continue; if (FD_ISSET(sockfd1, &rset)) //Para el caso de que uno de ellos escriba algo if ((n=read(sockfd1, msg,1024))==0){ //Proceso de cierre en caso de FIN José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 4 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes close(sockfd1); FD_CLR(sockfd1,&allset); client[i]=-1; }else{ j=0; while(j<=maxi){ //Envío al resto de clientes if(sockfd2=client[j]>0) if(client[j]!=sockfd1) //NO se transmite al origen write (sockfd2, msg, 1024); j++; } } } José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 5 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes SEPTIEMBRE 2003 Se desea desarrollar un servidor de un servicio de transmisión de datos bancarios. En concreto, el servicio consiste en recoger el número secreto que el cliente teclea en un cajero automático y comprobar que efectivamente es ese el número secreto de ese cliente. Así, el servidor recogerá la información de número de tarjeta y del número secreto de cada uno de los cajeros y enviará la confirmación con un “RIGHT” o “WRONG” según sea el número correcto o no. La lista de números secretos se pasa al servidor (no hay que programarla), donde en cada elemento de la lista se identifica el número de tarjeta y el número secreto según la estructura “struct tarjeta”. Las conexiones se realizan sobre comunicaciones UDP ya que la transmisión de información debe ser rápida. Sin embargo, se debe asegurar que el mensaje de respuesta “RIGHT” o “WRONG” sí que llegue por lo que se debe implementar un sistema de confirmación de recepción de dicho mensaje. Se debe esperar la confirmación no más de 5 segundos utilizando para ello la función “select”. Se supone que cada cajero es un único proceso que transmite los números de tarjeta y secreto en un único mensaje y que recibe el mensaje RIGHT o WRONG. Si recibe dicho mensaje envía un mensaje indicando “OK”. En el caso de no recibirlo en un periodo de tiempo de 8 segundos volverá a ejecutar la petición. #include <sys/socket.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <unistd.h> #include <time.h> #include <sys/select.h> #define MSG_SIZE 12 //Tamaño máximo del mensaje de texto #define SERVER_PORT 3000 #define RIGHT 1 #define WRONG 0 int main (int argc, char **argv) { struct tarjeta { long numero_tarjeta; int numero_secreto; struct tarjeta* siguiente; }; struct tarjeta2 { long numero_tarjeta2; int numero_secreto2; }; struct lista { struct tarjeta *primera; struct tarjeta *ultima; }; struct lista lista_tarjeta; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 6 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes struct tarjeta * comparativa; struct tarjeta2 * datos_cajero; int n, maxfd, sockfd, respuesta; char *confirmacion; int data, envio; fd_set rset; socklen_t clilen; struct sockaddr_in servaddr; struct sockaddr client; struct timeval tiempo_espera; if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= htonl (INADDR_ANY); servaddr.sin_port= htons (SERVER_PORT); if (bind (sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in))<0) { printf("ERROR \n"); exit(1); } // Código reservado para el funcionamiento del servidor close (sockfd); } José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 7 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes C) Funcionamiento del servidor. for (;;){ data=recvfrom (sockfd, datos_cajero, MSG_SIZE, 0, client, cli_len); //Preparado recibir datos if (data != sizeof (struct tarjeta)) { printf (“ERROR \n); continue; } //Se comprueban datos son correctos. Comparativa=lista_tarjeta->primera; //Inicialización de variables respuesta = WRONG; FD_SET(sockfd, &rset); tiempo_espera.tv_sec= 5; tiempo_espera.tv_usec=0; while (comparativa!= NULL) { //Comparar valores if ( comparativa->numero_tarjeta == datos_cajero->numero_tarjeta2){ if (comparativa ->numero_secreto==datos_cajero->numero_secreto2)respuesta =RIGHT; else respuesta = WRONG; break; } comparativa=comparativa->siguiente; } if (respuesta==RIGHT) //Se envía respuesta. envio= sendto (sockfd, “RIGHT”, strlen(“RIGHT”), 0, client, sizeof(&clilen)); else envio= sendto (sockfd, “WRONG”, strlen(“WRONG”), 0, client, sizeof(&clilen)); nready= select (maxfd+1, &rset, NULL, NULL, &tiempo_espera); // Proceso de confirmación . Se espera. if (nready==0) continue; // Se termina por Timeout if (FD_ISSET(sockfd, &rset)) { //Llega respuesta. Se confirma que es buena. recvfrom (sockfd, confirmacion, 2, 0, client, cli_len); if (strcmp(&confirmacion, “OK”)) continue; else{ printf (“ERROR”); continue; } } // Fin proceso de confirmación } // Fin del servidor José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 8 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 9 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 25 DE JUNIO DE 2004 Se desea desarrollar el software de comunicaciones de un cliente de un servicio de cajero automático bancario. En concreto, el servicio consiste en recoger el número de tarjeta que se obtiene al introducir la tarjeta del usuario y el número secreto que el cliente teclea en el teclado. Para cada evento se asigna estáticamente un descriptor que se usarán para leer los datos de entrada (número de tarjeta y número secreto). A continuación se deberá enviar al servidor esa información. La información se transmite a través de un socket UDP que conectará con el servidor y le transmitirá los datos a través de una estructura “struct tarjeta2”. El cajero automático deberá quedar bloqueado a través de la función “select” durante 8 segundos esperando la respuesta “RIGHT” o ”WRONG” dependiendo de si el número secreto es correcto o no. En caso de que no llegue dicha respuesta o se reciba errónea se volverá a realizar la petición. Otra información: #define teclado 0 #define numerotarjeta 3 #define servidor “192.168.5.254” #include <sys/socket.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <unistd.h> #include <time.h> #include <sys/select.h> #define TECLADO 0 //descriptor correspondiente a la entrada estándar. #define NUMEROTARJETA 3 //descriptor correspondiente a la entrada del lector de la tarjeta de crédito. #define SERVER_PORT 3000 //Número de puerto (indiferente). #define SERVIDOR “192.168.5.354” // Servidor del servicio de datos bancarios int main (int argc, char **argv) { struct tarjeta2 { long numero_tarjeta; int numero_secreto; }; struct tarjeta2 * datos_envio; char * respuesta; long *numero_tarjeta_in; int *numero_secreto_in; int n_ready; fd_set rset; socklen_t servlen; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 10 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes struct sockaddr_in servaddr; struct timeval tiempo_espera; if (read (NUMEROTARJETA, numero_tarjeta_in, sizeof(numero_tarjeta_in)) < sizeof (long)) { printf (“Error, tarjeta no válida\n “); exit(1); } if (read (TECLADO, numero_secreto_in, sizeof(numero_secreto_in)) < sizeof(int)) { printf (“Error, numero secreto incorrecto \n”); exit(1); } if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { printf ("ERROR \n"; exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port= htons (SERVER_PORT); datos_envio-> numero_tarjeta= *numero_tarjeta_in; datos_envio->numero_secreto= *numero_secreto_in; for (;;){ if (sendto (sockfd, datos_envio, sizeof (struct tarjeta2),0, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) <0) { printf (“Servidor fuera de servicio, espere mejor ocasión \n”); exit (1); } tiempo_espera.tv_sec= 8; tiempo_espera.tv_usec=0; FD_ZERO (&rset); FD_SET(sockfd, &rset); nbytes=strlen(“RIGHT”); nready= select (maxfd+1, &rset, NULL, NULL, &tiempo_espera); if (n_ready<0) { printf (“Error de datos, no se puede atender su petición\n”); exit(1); } else if (n_ready==0) { printf (“Servidor ocupado. Espere una nueva petición \n”); continue; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 11 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } if (FD_ISSET (sockfd, &rset)) { if (recvfrom (sockfd, respuesta, nbytes, 0, (struct sockaddr *) &servaddr, servlen) < nbytes){ printf (“Error, en datos de servidor\n”); continue; } if (strcmp (respuesta, “RIGHT”)==0 || strcmp (respuesta, “WRONG”)==0) { printf (“Servidor activo, llamada correcta. \n”); break; }else{ continue; } //Se recibe algo pero no es lo esperado } } } José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 12 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 18 DE DICIEMBRE DE 2004 Se diseña un servidor central concurrente TCP destinado al control automático de una central de envasado de zumos naturales. Como existen diversos tipos de zumos (N) existen N líneas de producción. El sistema se detalla en el gráfico: Cada operario tiene acceso al control sobre todas y cada una de las líneas de producción según le convenga en cada instante. Por tanto el servidor debe: − Gestionar las conexiones (sockets) permanentes con las líneas. Éstas se conectan inmediatamente al arrancar el sistema y no se desconectan salvo error o cierre. Habrá un total de n conexiones de ese tipo. Su conexión no forma parte del problema. Asignar el descriptor de cada línea a n+3 siendo n el número de línea, entre 1 y N (p. ej. Para la línea 1 su descriptor es 4, para la línea 2, el descriptor es 5, etc.). − Aceptar y gestionar las conexiones de los operarios, hasta un total de 4. − Recoger las órdenes de los operarios, transmitírselas a las líneas, esperar por las respuestas de las líneas y reenviarlas al operario que las solicitó (de forma concurrente). Se pide: A) Flujograma de funcionamiento del servidor. Visualiza la gestión de conexiones concurrentes y el servicio ofrecido a los operarios. Supóngase respuestas de las líneas inmediatas. (20%) B) Código del arranque del servidor concurrente y establecimiento de la conexión de los operarios. Recuerde que además hay N conexiones establecidas para las líneas (éstas no hay que conectarlas). (20%) C) Servicio a los usuarios. Código del programa necesario para que los usuarios puedan solicitar y recibir información de las líneas que le interesen (sólo de una por petición). Suponer que las respuestas de las líneas se producen de forma inmediata. (25%) D) Considerar ahora que el tiempo de respuestas de las líneas es elevado. Modificar el código para que el servidor siga funcionando de forma concurrente a pesar de este problema, es decir, que el servidor no se bloquee esperando las respuestas de las líneas. No se limita el tiempo de respuesta de las líneas y cada línea acepta sólo una petición simultánea. (25%) E) Código de desconexión de operarios propio de un servidor concurrente. (10%) Otra información: #define N 20 #define MSG_SIZE 1024 //Tamaño máximo de los mensajes #define PUERTO 3000 #define SERVIDOR “192.168.5.254” NOTAS IMPORTANTES: 1.- Los mensajes que transmite el operario, se pueden retransmitir a las líneas de productos tal y como llegan. Idem para las respuestas de las líneas. Se consideran mensajes de texto. 2.- Antes de transmitir una orden, el operario envía un “int” identificando la línea (n) a la que se está refiriendo. Mientras no cambie, todos los mensajes de ese operario se refieren a la última línea identificada. El envío del número de línea y del mensaje se realiza de forma consecutiva e inmediata (no es necesario ocuparse de la concurrencia en este período). 3.- NO es necesario incluir las macros y librerías habituales en el código de la solución. #include <sys/socket.h> José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 13 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes #include <sys/types.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <unistd.h> #include <sys/select.h> #define LISTENQ 4 // Tamaño de lista de entrada de conexiones. Como no se indica nada se asigna 4. #define MAXOPERARIO 4 // Número máximo de operarios #define MSG_SIZE 1024 // Tamaño máximo del mensaje de texto, válido para mensajes de operarios y de // líneas. #define SERVER_PORT 3000 #define SERVIDOR “192.168.5.254” #define N 20 int main (int argc, char **argv) { int i, maxi, maxfd, listenfd, connfd, sockfd, nready; int *linea_solicitada; int client[MAXOPERARIO]; // Array de Operarios int client2[MAXOPERARIO]; //Sockets (o línea) con los que se comunica cada operario. int operario[N]; //Necesario para saber a cada línea quién le ha preguntado int linea[N]; // Necesario para asignar a cada línea un descriptor. Se podría hacer: (descriptor =n+3); ssize_t len; fd_set rset, allset; char msg_env[MSG_SIZE]; char * msg_rec; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"; exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr=htonl (INADDR_ANY); // o bien servaddr.sin_addr.s_addr = inet_addr(SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 14 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los 4 posibles operarios. maxfd=listenfd; maxi=-1; for (i=0; i<MAXOPERARIO;i++){ //Inicialización de los arrays de clientes client[i]=-1; client2[i]=-1; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); for (i=0; i<N; i++) linea[i]=i+4; //Se asigna descriptor a cada línea, n+3 (como el array empieza en 0 => i+4) maxfd=N+3; //Se supone que las 20 líneas se han conectado ya, luego maxfd es igual al último descriptor. for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset){ //OPERARIO NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el operario for (i=0; i<MAXOPERARIO; i++) //Actualización del array if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; // Los operarios van después de las líneas if (i>maxi) maxi=i; } if (--nready<=0) continue; //Previsión para más de una interrupción /* ESPACIO RESERVADO PARA EL PROCESADO DEL SERVIDOR*/ } //Del bucle principal José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 15 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes ----------------------for (i=0; i<=maxi; i++){ if ((sockfd1=client[i])<0) // Se van a comprobar todos los OPERARIOS continue; if (FD_ISSET(sockfd1, &rset)) //Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec,MSG_SIZE))==0){ //Proceso de cierre en caso de FIN DEL OPERARIO (APARTADO E) close(sockfd1); FD_CLR(sockfd1,&allset); client[i]=-1; client2[i]=-1; if (maxi==i) --maxi; } if (--nready<=0) continue; else break; else{ if (len==sizeof(int)) { // Se recibe el número de línea al que se quiere dirigir linea_solicitada=(int *) &msg_rec; // Se pasa a apuntar en formato int. Ahora ya se puede dirigir el mensaje. client2[i]=linea[*linea_solicitada-1]; // Socket de la línea que quiere el operario se guarda en client2. len=read(sockfd1, msg_rec, MSG_SIZE); // Se lee el mensaje del operario. Se puede hacer control } // de errores. write (client2[i], msg_rec, len+1); //Se envía el mensaje a la línea. /* Las dos próximas líneas no se aplican en el apartado D */ len=read(client2[i], msg_env, MSG_SIZE); //Esperamos recibir el mensaje de la línea. write(sockfd1, msg_env, len+1); //Envíamos mensaje al operario. } //FIN del servicio al operario if (--nready<=0) continue; //Previsión para más de un operario simultáneo. } // Fin del for de atención a los usuarios ------------------------------------José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 16 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes for (i=0; i<=maxi; i++){ if ((sockfd1=client[i])<0) // Se van a comprobar todos los OPERARIOS continue; if (FD_ISSET(sockfd1, &rset)) //Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec,MSG_SIZE))==0){ //Proceso de cierre en caso de FIN DEL OPERARIO (APARTADO E) close(sockfd1); FD_CLR(sockfd1,&allset); client[i]=-1; client2[i]=-1; if (maxi==i) --maxi; } if (--nready<=0) continue; else break; else{ if (len==sizeof(int)) { // Se recibe el número de línea al que se quiere dirigir linea_solicitada=(int *) &msg_rec; // Se pasa a apuntar en formato int. Ahora ya se puede dirigir el mensaje. client2[i]=linea[*linea_solicitada-1]; // Socket de la línea que quiere el operario se guarda en client2. len=read(sockfd1, msg_rec, MSG_SIZE); // Se lee el mensaje del operario. Se puede hacer control } // de errores. write (client2[i], msg_rec, len+1); //Se envía el mensaje a la línea. if (operario[client2[i]] < 0) //Por si la línea estuviera ya ocupada. operario[client2[i]-4]=sockfd1; // actualización del array donde se guardan los operarios que solicitaron servicio para saber quién mandó el mensaje. FD_SET(client2[i], &allset); // Para que el descriptor del socket de esa línea pase a ser atendido. /* ATENCIÓN A LAS LÍNEAS */ for (j=0; j<N; j++){ if ((sockfd1 =linea[j])<0) // Se van a comprobar todos las LÍNEAS continue; if (FD_ISSET(sockfd1, &rset)) //Para el caso de que uno de las líneas haya mandado algo if ((len=read(sockfd1, msg_rec, MSG_SIZE))==0){ //Se leen los datos close(sockfd1); FD_CLR(sockfd1,&allset); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 17 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes linea[j]=-1; //Proceso de cierre en caso de FIN DE LÍNEA (APARTADO E) }else{ write (operario[j], msg_rec, len+1); FD_CLR(sockfd1,&allset); } } } //FIN del servicio al operario if (--nready<=0) continue; //Previsión para más de un operario simultáneo. } // Fin del for de atención a los usuarios José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 18 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 18 DE DICIEMBRE DE 2004 Se diseña un único servidor central concurrente TCP (sin generar nuevos procesos) destinado al control de la automatización de una empresa química. Como existen diversas máquinas para su control (N) existen N conexiones, una para cada máquina. El sistema se detalla en el gráfico: Cada operario tiene acceso al control sobre todas y cada una de las máquinas según le convenga en cada instante. Por tanto el servidor debe: − Aceptar y gestionar las conexiones (sockets) con las máquinas. Éstas se conectan independientemente entre ellas y lo hacen una vez hayan arrancado y se hayan configurado por sí mismas. Habrá un total de N conexiones de ese tipo. Sus descriptores van desde 4 hasta N+3. − Aceptar y gestionar las conexiones de los operarios, hasta un total de P conexiones de operarios. A los operarios se le asigna descriptor desde N+4 en adelante. − Recoger las órdenes de los operarios, transmitírselas a las máquinas, esperar por las respuestas de éstas y reenviarlas al operario que las solicitó (de forma concurrente). − La transmisión de las órdenes a las máquinas se realiza inmediatamente recibidas desde el operario. Las respuestas de las máquinas se reciben también de forma inmediata y se envían a su vez a los operarios ordenantes. Se pide: A) Flujograma de funcionamiento del servidor. Visualiza la gestión de conexiones concurrentes tanto de máquinas como de operarios y el servicio ofrecido a los operarios. Se valorará el utilizar un cronograma de apoyo sobre el funcionamiento del servidor. El proceso se realiza “estáticamente” para el servidor, es decir, que primero se conectan todas las máquinas (N) y luego todos los operario (P). Suponer máquinas desocupadas cuando se les envía una petición. (20%) B) Código del arranque del servidor concurrente y establecimiento de la conexión de las máquinas y de los operarios.(20%) C) Código de servicio a los usuarios. Código del programa necesario para que los usuarios puedan enviar información al servidor y que éste lo reenvíe a las máquinas (lo referente a recibir el número de máquina y mensaje y transmitir dicho mensaje a la máquina). Incluye también el código para que las máquinas respondan de forma inmediata y reenvío de las respuestas a los operarios. Controlar el caso de que la máquina no esté conectada. Supóngase que las máquinas están desocupadas. (25%) D) Flujograma de funcionamiento en el caso de que la conexión de las líneas y operarios se haga de forma aleatoria. En este caso, el primer mensaje después de la conexión de cada uno de los extremos es OPERARIO o MAQUINA según sea operario o máquina seguido del número de operario o máquina correspondiente. De esta formas los descriptores de máquinas y operarios no son consecutivos y pasan a estar mezclados. Destaca claramente el control de este hecho. (15%) E) Modifica el código de los apartados B y C cuando la conexión de los operarios y máquinas se realice de forma aleatoria. Presta especial atención al establecimiento de la conexión, distinción entre máquinas y operarios y la existencia de las conexiones con operarios y máquinas cuando se realiza el servicio. (20%) Otra información: José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 19 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes #define MSG_SIZE 1024 //Tamaño máximo de los mensajes de operarios a máquinas y viceversa #define PUERTO 3000 //Puerto del servicio #define SERVIDOR “192.168.5.254” //Dirección IP de la máquina servidora NOTAS IMPORTANTES: 1.- Los mensajes que transmite el operario, se pueden retransmitir a las máquinas tal y como llegan. Idem para las respuestas de las máquinas. Se consideran mensajes de texto. 2.- Antes de transmitir una orden, el operario envía un “int” identificando la máquina (n) a la que se está refiriendo. Por simplicidad, el operario siempre envía el número de máquina antes de una orden. El envío del número de máquina y del mensaje se realiza de forma consecutiva e inmediata en mensajes distintos (no es necesario ocuparse de la concurrencia en este período). 3.- Cada operario sólo puede enviar un mensaje cada vez y esperar una sola respuesta. 4.- NO es necesario incluir las macros y librerías habituales en el código de la solución. 5.- P+N<1020. #define P //Número máximo de operarios #define N // Número de máquinas #define LISTENQ P+N // Tamaño de lista de entrada de conexiones. Libre para aceptarlos todos a la vez #define MAXOPERARIO P // Número máximo de operarios #define MSG_SIZE 1024 // Tamaño máximo del mensaje de texto, válido para mensajes de operarios y de máquinas. #define SERVER_PORT 3000 #define SERVIDOR “192.168.5.254” int main (int argc, char **argv) { int i, maxi, maxfd, listenfd, connfd, sockfd, nready, sockfd1; int *maq_solicitada; int conexion_maquinas_completo=0; int client[MAXOPERARIO]; //Array de descriptores de los operarios. int machine[N]; //Array de descriptores de las máquinas. int client2[MAXOPERARIO]; //Sockets (o máquina) con los que se comunica cada operario. int operario[N]; //Necesario para saber a cada máquina quién le ha preguntado ssize_t len; fd_set rset, allset, writeset, writeallset; char msg_env[MSG_SIZE]; char * msg_rec[P]; //Array de mensajes recibidos de cada operario. socklen_t clilen; struct sockaddr_in cliaddr, servaddr; if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0 || (listenfd>2)) { printf ("ERROR \n"; exit(1); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 20 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr = inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in))<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los 4 posibles operarios. maxfd=listenfd; maxi=-1; for (i=0; i<MAXOPERARIO;i++){ //Inicialización de los arrays referentes a los operarios client[i]=-1; client2[i]=-1; } for (i=0; i<N;i++){ //Inicialización de los arrays de las maquinas machine[i]=-1; operario[i]=-1; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); maxfd=listenfd; //La única conectada for(;;){ rset=allset; nready=select(maxfd+1,&rset,NULL,NULL,NULL); if (FD_ISSET(listenfd,&rset)){ clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); if (!conexion_maquina_completo) {//Si es máquina for (i=0; i<N; i++)//Actualización del array de máquinas if (machine[i]<0) { machine[i]=connfd; break; }//No se actualiza el conjunto allset porque no es necesario. if (i==N) conexion_maquina_completo=1; //Actualización fin de conexión de máquinas José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 21 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if (i>maxi) maxi=i; }else {// Es un operario for (i=0; i<MAXOPERARIO; i++)//Actualización del array if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset);//Actualización del conjunto de descriptores if (connfd > maxfd)//Actualización de variables maxfd=connfd;// Los operarios van después de las máquinas if ((i+N)>maxi) maxi=i+N; } if (--nready<=0) continue;//Previsión para más de una interrupción } /* ESPACIO RESERVADO PARA EL PROCESADO DEL SERVIDOR*/ } //Del bucle principal } //Del main. C) /* CÓDIGO SERVIDOR PARA ATENDER LOS MENSAJES DE CADA OPERARIO*/ for (i=N+3; i<=maxi; i++){ // Se van a comprobar todos los OPERARIOS if ((sockfd1 =client[i-N-3])<0) continue; if (FD_ISSET(sockfd1, &rset)){ //Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec, MSG_SIZE))>0){ if (len==sizeof(int)) { maq_solicitada=(int *) &msg_rec; client2[i]=machine[*maq_solicitada-1]; if (machine[*maq_solicitada-1]<0) { --nready; continue; } len=read(sockfd1, msg_rec, MSG_SIZE); // control de errores. write (client2[i], msg_rec, len+1); //TX Mensaje. len=read(client2[i], msg_env, MSG_SIZE); write(sockfd1, msg_env, len+1); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 22 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } if (--nready<=0) continue; } } } D) for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL , NULL, NULL); //Bloqueo en espera de entradas o salidas if ( FD_ISSET(listenfd, &rset){ //OPERARIO NUEVO o Máquina nueva clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta la conexión for (i=0; i<N; i++)//Actualización del array de máquinas if (conexiones[i]<0) { conexiones[i]=connfd; break; }//No se actualiza el conjunto allset porque no es necesario. if (i==N+P) conexion =1; //Actualización fin de conexión posibles if (i>maxi) maxi=i; FD_SET(connfd,&allset); if (connfd > maxfd) maxfd=connfd; if (--nready<=0) continue; } for (i=0; i<=maxi; i++){ if ((sockfd1 =conexiones[i])<0) continue; //Actualización del conjunto de descriptores //Actualización de variables // Los operarios van después de las máquinas //Previsión para más de una interrupción // Se van a comprobar todos los OPERARIOS if (FD_ISSET(sockfd1, &rset)){//Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec, MSG_SIZE))==sizeof (“OPERARIO”)){ read(sockfd1, msg_rec, MSG_SIZE); num_operario=(int *) &msg_rec; client[*num_operario-1]=sockfd1; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 23 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Tipo_conexion[i]=1; }else if(len==sizeof(“MAQUINA”){ read(sockfd1, msg_rec, MSG_SIZE); num_maquina=(int *) &msg_rec; maquina[*num_maquina-1]=sockfd1; Tipo_conexion[i]=0; FD_CLR(&allset, sockfd1); } //Las máquinas no hay que escucharlas else{ if (len==sizeof(int)) { client2[i]=maquina[*maq_solicitada-1 if (maquina[*maq_solicitada-1]<0) { --nready; continue; } sock_maquina=maquina[*maq_solicitada-1]; for (int k=0; k<N+P; k++){ sock_conexiones=conexiones[k]; if (sock_conexiones==sock_maquina) break; } } if(tipo_conexión[k]>0){ --ready; continue; } maq_solicitada=(int *) &msg_rec; // Se pasa a apuntar en formato int. Ahora ya se puede dirigir el len=read(sockfd1, msg_rec, MSG_SIZE); write (client2[i], msg_rec, len+1); //TX Mensaje. len=read(client2[i], msg_env, MSG_SIZE); write(sockfd1, msg_env, len+1); } if (--nready<=0) continue; } } //Del bucle principal } //Del main. José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 24 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 28 DE JUNIO DE 2005 – EJERCICIO 1 Se diseña un servidor central concurrente TCP (puerto 5999) destinado al servicio de telefonía móvil. El servicio acepta la conexión de los distintos clientes y los mantiene conectados mientras no reciba la acción de desconexión. El gráfico representa el sistema una vez conectados los usuarios: Entre las tareas del servidor, se encuentran: − Gestionar las conexiones (sockets) permanentes con los usuarios. Éstos se conectan cuando desean tener acceso a la red. Habrá un total de N conexiones de este tipo. − Gestionar la conexión con el resto de la red a través del descriptor 500 (fijo y siempre activo). − Gestionar el establecimiento de las conexiones entre usuarios inscritos en el propio servidor y entre usuarios locales y externos. Cuando un usuario desea la conexión manda un número destino. Con el número, se comprueba si el destino pertenece a este servidor y, en caso negativo, se manda al resto de la red, estableciéndose, en su caso, la comunicación a través de un nuevo descriptor para el usuario destino. No se contempla el caso de peticiones desde usuarios externos. Se pide: A) Código para aceptar la conexión de los usuarios y proporcionar la concurrencia. El “resto de la red” está conectada desde el arranque del servidor. (20%) B) Código de establecimiento de las llamadas entre los usuarios locales. No incluya la gestión de las llamadas una vez establecidas, sólo lo referente a la recepción de los números, y petición al usuario destino (con el número origen) y espera de la respuesta (no hay que responder al usuario origen). La conexión se realiza si se recibe un “SI” y no se realiza si es un “NO”. (20%) C) Código de establecimiento de las llamadas con usuarios remotos. En este caso las peticiones hay que encaminarlas por el descriptor “resto de la red”. La respuesta en este caso puede ser un “NO” si es negativa con lo que se rechaza, y en caso afirmativo se recibe un paquete de conexión SYN a través del descriptor “resto de la red”. En este caso se procederá a la conexión del nuevo cliente y pasará a ser un usuario local más. No hay que responder al cliente origen.(20%) Otra información: #define N 20 #define SERVIDOR “192.168.5.254” #define N 20 #define LISTENQ N // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N a la vez. #define SERVER_PORT 5999 //Dato #define SERVIDOR “192.168.5.254” #define RESTO 500 //Descriptor del resto de la red #define MSG_SIZE 1024 //No se dice nada, mínimo mayor de 4 int main (int argc, char **argv) { int i, j, maxi, maxfd, listenfd, connfd, sockfd, sockfd1, nready,*numero, numero_resto; int client [N]; // Array de descriptores de cada línea int numeros[N]; //Posición-client<->Número José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 25 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes int conexiones [N]; //Relacionales entre números int masclient [FD_SETSIZE]; //Para clientes externos que se conecten (apartado C) int conexiones2 [FD_SETSIZE];//Para los relacionales de los externos (apartado C) int numeros2 [FD_SETSIZE];// Para los números externos (apartado C) ssize_t len; fd_set rset, allset; char * msg_env; //Mensaje enviado de conexión char * msg_rec; // Mensaje recibido de conexión char *valor1, *valor2; //Auxiliares para formar mensaje socklen_t clilen; struct sockaddr_in cliaddr, servaddr; if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"; exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); maxfd=listenfd; maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; numeros[i]=-1; conexiones [i]=-1; } FD_ZERO(&allset); FD_ZERO(&rset); //Inicialización de los conjuntos de descriptores //Preparado para aceptar la entrada de los posibles clientes. FD_SET(listenfd, &allset); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 26 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset){ //USUARIO NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario for (i=0; i<MAXOPERARIO; i++)//Actualización del array if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset);//Actualización del conjunto de descriptores if (connfd > maxfd)//Actualización de variables maxfd=connfd;// Los operarios van después de las líneas if (i>maxi) maxi=i; if (--nready<=0) continue;//Previsión para más de una interrupción } /* ESPACIO RESERVADO PARA EL PROCESADO DEL SERVIDOR*/ } //Del bucle principal } //Del main B) /* CÓDIGO SERVIDOR PARA ATENDER LAS PETICIONES DE CADA CLIENTE*/ for (i=0; i<=maxi; i++){ if ((sockfd1 =client[i])<0) continue; // Se van a comprobar todos los CLIENTES LOCALES if (FD_ISSET(sockfd1, &rset))//Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec,MSG_SIZE))==0){ close(sockfd1); FD_CLR(sockfd1,&allset); client[i]=-1; numeros[i]=-1; if (maxi==i) --maxi; } if (--nready<=0) break; else continue; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 27 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes else{ if (conexiones[i]<0) //Conexiones. No conversación. if (len==sizeof(int)){ // Se recibe un número de teléfono if (numeros[i]<0){ numero=(int *) &msg_rec; numeros[i]=*numero;// Actualización número propio if (--nready<=0) break; else continue; }else{// No es el número propio, es el destino numero=(int *) &msg_rec; conexiones[i]=numero;// Actualización conexiones j=0; while (numeros[j]!=numero) j++; if (j<20) //Número local write(client[j], &numeros[i], sizeof(numeros[i])); if (j>=20){ //Número externo valor1=(char*)&numeros[i]; valor2=(char *)conexiones[i]; msg_env=strcat(valor1, “:”); msg_env=strcat(msg_env, valor2); write(RESTO, msg_env, strlen(msg_env)); //Envíamos mensaje de conexión . FD_SET(RESTO, &allset); //Se activa el descriptor del RESTO de la red. Solución óptima numero_resto=numero; } //Variable para actualizar la petición if (--nready<=0) break; else continue; } //Previsión para más de una interrupción else // (sizeof(int)) No es número de télefono, será respuesta... if (len=strlen(“SI”)) // Se puede comprobar que es lo esperado... if (strcmp (msg_rec,”SI”)==0){ // Es un SI j=0; while (conexiones[j]!=numeros[i]) j++; //Actualización de arrays de conexión conexiones[i] = numeros[j]; }else{ //Es un NO j=0; while (conexiones[j]!=numeros[i]) j++; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 28 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes //Actualización de arrays no conexión conexiones[j] = -1; } else break; //error else // De conexiones... ES TEXTO if (--nready<=0) continue;//Previsión para más de un operario simultáneo. } // Fin del for de atención a los usuarios C) Ahora las llamadas pueden ser externas... if (FD_ISSET(RESTO, &rset)) {//Para el caso de que uno de ellos escriba algo if ((len=read(RESTO, msg_rec,MSG_SIZE))!=0) // Va a ser un “NO” if (strcmp(msg_rec,“NO”)==0){ // Se puede comprobar que es lo esperado... FD_CLR (RESTO, &allset); j=0; while (conexiones[j]!=numero_resto) j++; //Actualización de arrays no conexión conexiones[j] = -1; }else continue; //del strcmp (caso de error), no es un “NO” y tampoco un SYN else{ //del read //Como se recibe len =0 y no puede ser un CLOSE, es el paquete SYN, con lo que deberemos hacer la //conexión. clilen=sizeof(cliaddr); connfd =accept(RESTO, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el operario for (i=0; i<(FD_SETSIZE); i++)//Actualización del array if (masclient[i]<0) {//Nuevo array, el viejo se queda pequeño masclient[i]=connfd; break; } FD_SET(connfd,&allset);//Actualización del conjunto de descriptores if (connfd > maxfd)//Actualización de variables maxfd=connfd;// Los operarios van después de las líneas if (i>maxi) maxi=i; //Faltaría añadir la conexión y el número a los nuevos arrays j=0; while (conexiones[j]!=numero_resto) j++; conexiones2 [i] =numeros[j]; numeros2 [i]= numero_resto; FD_CLR (RESTO, &allset); if (--nready<=0) continue; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 29 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } //Previsión para más de una interrupción que realmente no existe //En este último caso en la gestión de la comunicación (no se pide) debería incluir la gestión no //sólo de los arrays conexiones, numeros y client, sino que además habría que tener en cuenta los // arrays masclient, conexiones2 y numeros2. José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 30 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Problema 2 (50% Ejercicios) Se pretende realizar un servidor NTP (servidor de tiempo de red) de forma que todas aquellas máquinas que ejecuten el cliente apropiado (que se puede descargar sin ningún tipo de restricción) se puedan sincronizar con esta máquina y se permita el mantenimiento de esta sincronización. La sincronización es necesaria por ejemplo para programación remota, en las que se evita generaciones de código posteriores en unas máquinas que en otras. En el funcionamiento de la aplicación una vez llega un nuevo cliente, éste no vuelven a transmitir nada más. Se pide: A) Explique razonadamente el tipo de protocolo a usar en esta aplicación. (10%) B) Realice el código necesario para que el servicio opere en el puerto 123 del servidor y sea capaz de mantener hasta 100 usuarios simultáneamente. Recuerde que el sistema será concurrente, por lo que prepárelo para ello. (10%) C) Realice el código necesario para que el servicio sea capaz de generar y enviar la información que ofrece esta aplicación, es decir, los valores temporales que sirvan de sincronización. Dicha información tiene esta estructura: struct timeval original | struct timeval actual El campo actual se obtiene de la ejecución del comando int gettimeofday(struct timeval *tv1, struct timezone *tv2) donde el parámetro tv1 devuelve la hora exacta, siendo original la hora exacta del momento en que llegó el nuevo cliente. (15%) D) Realice el código para que la aplicación sea capaz de mantener el servicio, reactualizando la información planteada cada 10 msec. de forma concurrente. (15%) Otra información: #define MSG_SIZE 32 //Tamaño de los mensajes #define Direccion_local “192.168.3.1” Considere los tiempos de ejecución de código despreciable. NOTA IMPORTANTE PARA LOS DOS PROBLEMAS: 1.- NO es necesario incluir las macros y librerías habituales en el código de la solución. #define MSG_SIZE 32 //Tamaño máximo de los mensajes #define Direccion_local “192.168.3.254” #define PUERTO_SERVIDOR 123 int main (int argc, char **argv) { int maxfd, listenfd, nready, i ; ssize_t len; fd_set rset; char msg_rec[MSG_SIZE]; // Mensajes recibidos José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 31 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes socklen_t clilen; char *buff; struct timeval *original[100]; //Hora de funcionamiento original struct sockaddr_in direcciones[100]; //Los usuarios posibles… struct sockaddr_in servaddr, cliaddr; struct timeval *tv1,*tv2,*tvselect ; //La variables temporales que se harán necesarias // Inicializaciones temporales tv1->tv_sec=0; tv1->tv_usec=0; tv2->tv_sec=0; tv2->tv_usec=0; nready=0; //La preparación para 100 clientes consiste en abrir el puerto 123 y crear los arrays para 100 posiciones. for (i=0; i<100;i++){ //Inicialización de los arrays de clientes original[i]=NULL; bzero(&direcciones[i],sizeof(struct sockaddr_in)); } //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (Direccion_local); servaddr.sin_port=htons(PUERTO_SERVIDOR); maxfd=-1 ; if((listenfd = socket(AF_INET,SOCK_DGRAM,0))<= 0) {printf ("ERROR \n"; exit(1);} if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))<0) {printf("ERROR \n"); exit (1);}; maxfd=listenfd; //Servidor UDP preparado msg_rec[0]=’\0’; gettimeofday(tv2, NULL); // Para el funcionamiento del timeout for(;;){ tvselect->tv_sec= 0; if (nready==0){ //se salio por timeout el valor son 10000 usecs tvselect->tv_usec=10000; tv1->tv_sec= tv2->tv_sec; tv1->tv_usec= tv2->tv_usec; } else //Si no es que expiró antes y hay que recalcular el timeout José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 32 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes tvselect->tv_usec= 10000-(tv2->tv_usec-tv1->tv_usec); FD_SET(listenfd,&rset); nready=select (maxfd+1, &rset, NULL, NULL, tvselect); if (nready==0) //Salta timeout //reenviar información for (i=0, i<maxi, i++){ buff=NULL; buff=strcat(buff, (char *) original[i]); n=gettimeofday(tv2, NULL); buff=strcat(buff, (char *)tv2); sendto(listenfd, buff, strlen (buff), 0, (struct sockaddr*)&direcciones[i], sizeof (struct sockaddr_in)); }; if (FD_ISSET(listenfd, &rset)) { //Se recibe algo -> NUEVO CLIENTE recvfrom (listenfd, msg_rec, MSG_SIZE, 0, (struct sockaddr*)&cliaddr, sizeof (struct sockaddr_in)); gettimeofday(tv2, NULL); direcciones [maxi]=cliaddr; original[maxi]=tv2; maxi++; buff=NULL; buff=strcat(buff, (char *)tv2); buff=strcat(buff, (char *)tv2); sendto(listenfd, buff, strlen (buff), 0, (struct sockaddr*)&cliaddr, sizeof (struct sockaddr_in)); }; } //Fin for }//Fin main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 33 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Problema 1 (50% Ejercicios) 29 DE JUNIO DE 2010 Se diseña un servicio TCP concurrente en el que los clientes se conectan a este servicio para descargarse información de aplicaciones propias del servicio que se genera de forma aleatoria. El gráfico representa las conexiones de las aplicaciones: Entre las tareas del servicio, se encuentran: − Gestionar las conexiones permanentes con los clientes. Éstos se conectan cuando desean acceder a la información de las aplicaciones. Habrá un total de N conexiones de este tipo en el servidor. − Gestionar la conexión de las aplicaciones de lectura (independientes de la aplicación servidor) que generan la información aleatoria. Éstas se conectan en cualquier momento sin que exista ninguna situación predeterminada previa. Habrá un total de M conexiones de este tipo. − Gestionar la transmisión de la información al cliente. Se pide: A) Código de aceptación de conexiones de los clientes y aplicaciones. No olvide realizar el proceso de forma concurrente, utilizando un único select. Los clientes se encuentran necesariamente en máquinas remotas del servidor. (15%) B) Código para la lectura de la información de las aplicaciones y reenvío a los clientes de este contenido de forma concurrente. Una vez el servicio recibe la información desde las aplicaciones, se procede al envío a todos los clientes. La información reenviada estará compuesta por el número de la aplicación, que es tomado del número de puerto de ésta, seguida de la información recibida según formato “PUERTO:INFORMACION”. Se mantendrá el uso de un único select. (15%) C) Ahora suponga que los clientes quieren que el servidor les filtre la información de forma que no reciban la información de todas las aplicaciones, sino sólo de algunas que cada cliente determine. Por ello, realice el código que permite que el cliente determine las aplicaciones de las que requiere la información mediante un paquete del formato “FILTRAR:PUERTO1:PUERTO2… :PUERTOM”, donde PUERTOX es el número de puerto de las aplicaciones en las que está interesado. (20%) Otra información: #define N 20 #define M 30 #define SERVIDOR “192.168.3.254” //Suponga que el servidor no tiene ningún otro inferfaz #define SERVER_PORT 6999 #define MSG_SIZE 256 // Tamaño máximo para todos los mensajes #define N 20 #define M 30 #define SERVIDOR “192.168.3.254” //Suponga que el servidor no tiene ningún otro inferfaz #define SERVER_PORT 6999 #define MSG_SIZE 256 // Tamaño máximo para todos los mensajes int main (int argc, char **argv) { José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 34 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes int i, j, maxi, maxj, maxfd, listenfd, connfd, sockfd1, nready, numero, valor; int client [N]; // Array de descriptores de los usuario int descriptores_aplicaciones[M]; //Se crea un array de “descriptores locales” para los servicios. int aplicaciones[M]; Array de los puertos de las aplicaciones. char* relaciones[N];//Array de relaciones de clientes, para cuando los clientes indiquen filtrar(apartado C) ssize_t len; buff[MSG_SIZE]; //Buffer para generar los mensajes fd_set rset, allset; char msg_rec[MSG_SIZE]; // Mensaje recibido socklen_t clilen; struct sockaddr_in cliaddr, servaddr; //Arranque del servidor concurrente if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) {printf ("ERROR \n"; exit(1);} bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); //htonl(INADDR_ANY); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) {printf("ERROR \n"); exit (1);} listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. maxfd=listenfd; maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; relaciones[i]=NULL; } for(i=0; i<M; i++){ aplicaciones [i]=-1; descritpres_aplicaciones[i]=-1; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas //Ahora la conexiones de clientes y aplicaciones if ( FD_ISSET(listenfd, &rset){ // NUEVO no se puede distinguir si es cliente o aplicación clilen=sizeof(cliaddr); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 35 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario if (!strcmp(inet_ntoa(cliaddr.sin_addr), SERVIDOR)){ //Es un cliente no aplicación for (i=0; i<N; i++) //Actualización del array if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; if (i>maxi) maxi=i; else{ // Es una aplicación no cliente for (i=0; j<M; j++) //Actualización del array if (descriptores_aplicaciones[j]<0) { descriptores_aplicaciones[j]=connfd; break; } aplicaciones[j]=ntohs(cliaddr.sin_port); //Guardamos el puerto; FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; if (i>maxj) maxj=j; }; if (--nready<=0) continue; //Previsión para más de una interrupción } for (j=0; j<maxj; j++){ if ((sockfd1 =descriptores_aplicaciones[j])<0) // Se van a comprobar todas los clientes continue; if (FD_ISSET(sockfd1, &rset)) //Se recibe algo if((len=read(sockfd1, msg_rec, MSG_SIZE-strlen((char *)&aplicaciones[j])-1)> 0) //Se lee. No es vacío msg_env[0]=’\0’; msg_env=strcat(msg_env, (char *)&aplicaciones[j]); msg_env=strcat(msg_env, “:”); msg_env=strcat(msg_env, msg_rec); for (i=0,i>maxi, i++) if (client[i]>0){ if(listado=strdup(relaciones[j])!=NULL); //HAY Filtrado José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 36 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes for (k=0, k<maxj, k++){ if (strtol(listado, listado, 10)==aplicaciones [k]){ write(client[i], msg_env, strlen(msg_env)); break; } listado++; if (listado==NULL) break; } }; }; //CÓDIGO atención clientes (filtrado). for (i=0; i<maxi; i++){ if ((sockfd1 =client[i])<0) // Se van a comprobar todas los clientes continue; if (FD_ISSET(sockfd1, &rset)) //Se recibe algo if((len=read(sockfd1, msg_rec, MSG_SIZE))> 0) //Se lee. No es vacío msg_rec=strchr(msr_rec, ‘:’)++; relaciones[i]=strdup(msg_rec); } // FIN ATENCIÓN CLIENTES if(listado=strdup(relaciones[j])!=NULL); //HAY Filtrado for (k=0, k<maxj, k++){ if (strtol(listado, listado, 10)==aplicaciones [k]){ break; } listado++; if (listado==NULL) break; } }// Fin for } // Fin main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 37 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 28 DE JUNIO DE 2005 – EJERCICIO 1 Se diseña un servidor central concurrente TCP (puerto 5999) destinado al servicio de telefonía móvil. El servicio acepta la conexión de los distintos clientes y los mantiene conectados mientras no reciba la acción de desconexión. El gráfico representa el sistema una vez conectados los usuarios: Entre las tareas del servidor, se encuentran: − Gestionar las conexiones (sockets) permanentes con los usuarios. Éstos se conectan cuando desean tener acceso a la red. Habrá un total de N conexiones de este tipo. − Gestionar la conexión con el resto de la red a través del descriptor 500 (fijo y siempre activo). − Gestionar el establecimiento de las conexiones entre usuarios inscritos en el propio servidor y entre usuarios locales y externos. Cuando un usuario desea la conexión manda un número destino. Con el número, se comprueba si el destino pertenece a este servidor y, en caso negativo, se manda al resto de la red, estableciéndose, en su caso, la comunicación a través de un nuevo descriptor para el usuario destino. No se contempla el caso de peticiones desde usuarios externos. Se pide: A) Código para aceptar la conexión de los usuarios y proporcionar la concurrencia. El “resto de la red” está conectada desde el arranque del servidor. (20%) B) Código de establecimiento de las llamadas entre los usuarios locales. No incluya la gestión de las llamadas una vez establecidas, sólo lo referente a la recepción de los números, y petición al usuario destino (con el número origen) y espera de la respuesta (no hay que responder al usuario origen). La conexión se realiza si se recibe un “SI” y no se realiza si es un “NO”. (20%) C) Código de establecimiento de las llamadas con usuarios remotos. En este caso las peticiones hay que encaminarlas por el descriptor “resto de la red”. La respuesta en este caso puede ser un “NO” si es negativa con lo que se rechaza, y en caso afirmativo se recibe un paquete de conexión SYN a través del descriptor “resto de la red”. En este caso se procederá a la conexión del nuevo cliente y pasará a ser un usuario local más. No hay que responder al cliente origen.(20%) Otra información: #define N 20 #define SERVIDOR “192.168.5.254” #define N 20 #define LISTENQ N // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N a la vez. #define SERVER_PORT 5999 //Dato #define SERVIDOR “192.168.5.254” #define RESTO 500 //Descriptor del resto de la red #define MSG_SIZE 1024 //No se dice nada, mínimo mayor de 4 int main (int argc, char **argv) { int i, j, maxi, maxfd, listenfd, connfd, sockfd, sockfd1, nready,*numero, numero_resto; int client [N]; // Array de descriptores de cada línea José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 38 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes int numeros[N]; //Posición-client<->Número int conexiones [N]; //Relacionales entre números int masclient [FD_SETSIZE]; //Para clientes externos que se conecten (apartado C) int conexiones2 [FD_SETSIZE];//Para los relacionales de los externos (apartado C) int numeros2 [FD_SETSIZE];// Para los números externos (apartado C) ssize_t len; fd_set rset, allset; char * msg_env; //Mensaje enviado de conexión char * msg_rec; // Mensaje recibido de conexión char *valor1, *valor2; //Auxiliares para formar mensaje socklen_t clilen; struct sockaddr_in cliaddr, servaddr; if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"; exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); maxfd=listenfd; maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; numeros[i]=-1; conexiones [i]=-1; } FD_ZERO(&allset); FD_ZERO(&rset); //Inicialización de los conjuntos de descriptores //Preparado para aceptar la entrada de los posibles clientes. José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 39 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes FD_SET(listenfd, &allset); for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset){ //USUARIO NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario for (i=0; i<MAXOPERARIO; i++)//Actualización del array if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset);//Actualización del conjunto de descriptores if (connfd > maxfd)//Actualización de variables maxfd=connfd;// Los operarios van después de las líneas if (i>maxi) maxi=i; if (--nready<=0) continue;//Previsión para más de una interrupción } /* ESPACIO RESERVADO PARA EL PROCESADO DEL SERVIDOR*/ } //Del bucle principal } //Del main B) /* CÓDIGO SERVIDOR PARA ATENDER LAS PETICIONES DE CADA CLIENTE*/ for (i=0; i<=maxi; i++){ if ((sockfd1 =client[i])<0) continue; // Se van a comprobar todos los CLIENTES LOCALES if (FD_ISSET(sockfd1, &rset))//Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec,MSG_SIZE))==0){ close(sockfd1); FD_CLR(sockfd1,&allset); client[i]=-1; numeros[i]=-1; if (maxi==i) --maxi; } if (--nready<=0) break; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 40 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes else continue; else{ if (conexiones[i]<0) //Conexiones. No conversación. if (len==sizeof(int)){ // Se recibe un número de teléfono if (numeros[i]<0){ numero=(int *) &msg_rec; numeros[i]=*numero;// Actualización número propio if (--nready<=0) break; else continue; }else{// No es el número propio, es el destino numero=(int *) &msg_rec; conexiones[i]=numero;// Actualización conexiones j=0; while (numeros[j]!=numero) j++; if (j<20) //Número local write(client[j], &numeros[i], sizeof(numeros[i])); if (j>=20){ //Número externo valor1=(char*)&numeros[i]; valor2=(char *)conexiones[i]; msg_env=strcat(valor1, “:”); msg_env=strcat(msg_env, valor2); write(RESTO, msg_env, strlen(msg_env)); //Envíamos mensaje de conexión . FD_SET(RESTO, &allset); //Se activa el descriptor del RESTO de la red. Solución óptima numero_resto=numero; } //Variable para actualizar la petición if (--nready<=0) break; else continue; } //Previsión para más de una interrupción else // (sizeof(int)) No es número de télefono, será respuesta... if (len=strlen(“SI”)) // Se puede comprobar que es lo esperado... if (strcmp (msg_rec,”SI”)==0){ // Es un SI j=0; while (conexiones[j]!=numeros[i]) j++; //Actualización de arrays de conexión conexiones[i] = numeros[j]; }else{ //Es un NO j=0; while (conexiones[j]!=numeros[i]) j++; //Actualización de arrays no conexión conexiones[j] = -1; } José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 41 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes else break; //error else // De conexiones... ES TEXTO if (--nready<=0) continue;//Previsión para más de un operario simultáneo. } // Fin del for de atención a los usuarios C) Ahora las llamadas pueden ser externas... if (FD_ISSET(RESTO, &rset)) {//Para el caso de que uno de ellos escriba algo if ((len=read(RESTO, msg_rec,MSG_SIZE))!=0) // Va a ser un “NO” if (strcmp(msg_rec,“NO”)==0){ // Se puede comprobar que es lo esperado... FD_CLR (RESTO, &allset); j=0; while (conexiones[j]!=numero_resto) j++; //Actualización de arrays no conexión conexiones[j] = -1; }else continue; //del strcmp (caso de error), no es un “NO” y tampoco un SYN else{ //del read //Como se recibe len =0 y no puede ser un CLOSE, es el paquete SYN, con lo que deberemos hacer la //conexión. clilen=sizeof(cliaddr); connfd =accept(RESTO, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el operario for (i=0; i<(FD_SETSIZE); i++)//Actualización del array if (masclient[i]<0) {//Nuevo array, el viejo se queda pequeño masclient[i]=connfd; break; } FD_SET(connfd,&allset);//Actualización del conjunto de descriptores if (connfd > maxfd)//Actualización de variables maxfd=connfd;// Los operarios van después de las líneas if (i>maxi) maxi=i; //Faltaría añadir la conexión y el número a los nuevos arrays j=0; while (conexiones[j]!=numero_resto) j++; conexiones2 [i] =numeros[j]; numeros2 [i]= numero_resto; FD_CLR (RESTO, &allset); if (--nready<=0) continue; } //Previsión para más de una interrupción que realmente no existe José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 42 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes //En este último caso en la gestión de la comunicación (no se pide) debería incluir la gestión no //sólo de los arrays conexiones, numeros y client, sino que además habría que tener en cuenta los // arrays masclient, conexiones2 y numeros2. José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 43 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Problema 2 (40%) Se diseña un servicio de telefonía móvil, en el que la estación base ofrece servicios muy diversos, entre los que se encuentran los mensajes de texto. Se pretende realizar el software de los terminales móviles, de manera que sean capaces en enviar y recibir los mensajes de texto referentes a este servicio. De esta forma, el sistema consiste en atender simultáneamente al usuario del teléfono móvil por si desea mandar el mensaje y atender al servidor por si es éste el que nos manda el mensaje de otro usuario. Se pide: A) Realice el código necesario de conexión del terminal al servidor y mantener la concurrencia entre el usuario local y el servidor conectado. (20%) B) Realice el código para mandar y recibir mensajes. En caso del envío, el teléfono incluye en el mensaje el propio número de teléfono de la forma: “Número_propio:mensaje”. De igual forma, en la recepción se recibe un mensaje del mismo tipo y se deben separar los dos campos, mostrando sólo el mensaje por la pantalla. (20%) Otra información: #define MSG_SIZE 1024 //Tamaño máximo de los mensajes #define PUERTO 3000 #define SERVIDOR “192.168.5.254” #define SERVER_PORT 3000 //Dato #define SERVIDOR “192.168.5.254” //Dato #define MSG_SIZE 1024 //Se sobreentiende que completo #define TECLADO 0 // Descriptor para el teclado #define PANTALLA 1 // Descriptor para la pantalla int main (int argc, char **argv) { int maxfd, listenfd, numero, sockfd1; char* numero propio; ssize_t len; fd_set rset, allset; char * msg_env; //Mensaje enviado de conexión char * msg_rec; // Mensaje recibido de conexión char *valor1, *valor2; //Auxiliares para formar mensaje socklen_t clilen; struct sockaddr_in servaddr; numero_propio= argv[1]; //Por ejemplo, se puede pasar así, no viene especificado en el enunciado. if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 44 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if(connect(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } if (listenfd>TECLADO) maxfd=listenfd; else maxfd =TECLADO; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; numeros[i]=-1; conexiones [i]=-1; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); //Socket hay que activarlo FD_SET(TECLADO, &allset); //Teclado hay que activarlo for(;;){ rset=allset; select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset)){ //SERVIDOR //ATENCIÓN A LA INTERRUPCIÓN DEL SERVIDOR, se recibe mensaje if (len=read(listenfd, msg_rec, MSG_SIZE)==0) // Caso de cierre close (listendfd); else{ // Mensaje msg_env=strchr(msg_rec, “:”); //Buscamos los “:” write(PANTALLA, msg_env++, strlen(msg_env)); } } if ( FD_ISSET(TECLADO, &rset)){ //USUARIO //ATENCIÓN A LA INTERRUPCIÓN DEL USUARIO, se tx mensaje if (len=read(TECLADO, msg_rec, MSG_SIZE-strlen(numero_propio)-1)==0){ // Caso de cierre close (listendfd); exit(1); }else{ // Mensaje valor=numero_propio; msg_env=strcat(valor, “:”); //Ponemos los “:” msg_env=strcat(msg_env,msg_rec); // Componemos el mensaje write(listenfd, msg_env, strlen(msg_env)); // Y tx al servidor José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 45 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } } } Fin del for } Fin del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 46 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 2 DE FEBRERO DE 2010 Problema 1 (50% Ejercicios) Se diseña un servicio TCP concurrente en el que el los clientes se conectan para acceder a información que están generando aplicaciones que corren de manera autónoma en la misma máquina en el que se ejecuta el servicio. El gráfico representa las conexiones de las aplicaciones: Entre las tareas del servicio, se encuentran: − Gestionar las conexiones permanentes con los clientes. Éstos se conectan cuando desean acceder a una aplicación. Habrá un total de N conexiones de este tipo en el servidor. − Gestionar la conexión con las aplicaciones suministradoras de información (independientes de la aplicación servidor). Éstas son conectadas cuando un cliente pide su contenido. − Gestionar la devolución del contenido a los clientes. También se realiza la gestión de un estadístico. Se pide: A) Código de aceptación de conexiones de los clientes y lectura del nombre de la aplicación de la que se lee la información. Este proceso se realiza de forma concurrente, con un único select. (20%) B) Código para la comunicación con las aplicaciones y lectura de su contenido. Una vez el servicio recibe el nombre de la aplicación, se procede a la conexión con la aplicación de lectura y lectura de los datos y transmisión de su contenido de forma concurrente. Para saber qué aplicación ha de vincularse, el nombre de la aplicación lleva un número en su nombre según formato: “nombreXX” que indica el número de aplicación que lee ese contenido. Se mantendrá el uso de un único select. (20%) C) Código para componer la temporización del tiempo de servicio. Para ello discretize el tiempo por una décima de segundo y obtenga el instante de comienzo de petición del cliente y el de devolución de la información. El tiempo será la diferencia de ambos. Informe de este tiempo en un mensaje explícito al usuario. (10%) Otra información: #define N 20 #define M 29 #define SERVIDOR “192.168.5.254” #define SERVER_PORT 2399 #define MSG_SIZE 256 // Tamaño máximo para todos los mensajes. #define APLICATTION_PORT 300M //Siendo M el número de la aplicación [3001..30M] #define N 20 //dato José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 47 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes #define M 29 //dato #define LISTENQ N // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N a la vez. #define SERVER_PORT 2399 //Dato #define APLICACION_PORT 3000 #define SERVIDOR “192.168.3.254” #define MSG_SIZE 256 //Tamaños maximos int main (int argc, char **argv) { int i, j, maxi, maxfd, listenfd, connfd, sockfd1, nready, numero, valor; int client [N]; // Array de descriptores de los usuario int descriptores_aplicaciones[M]; //Se crea un array de “descriptores locales” para las aplicaciones. // char *aplicaciones[M]; Nombres de aplicaciones. No hace falta guardarlos. // int relaciones[N]; //Array de relaciones de clientes, para relacionar cliente->aplicacion int clientes_destinos[M]; // Como para el apartado C hay que relacionar directamente todo, se hace un segundo // array de relaciones aplicación->cliente long tiempo_final[N]; //Para el cálculo del retardo de servicio long tiempo_comienzo[N[; //Guardar tiempo de apertura del servicio ssize_t len; char buff[MSG_SIZE]; fd_set rset, allset; char msg_rec[MSG_SIZE]; // Mensaje recibido socklen_t clilen; struct sockaddr_in cliaddr, servaddr; struct timeval tv; //Arranque del servidor concurrente if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0){ printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. maxfd=listenfd; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 48 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; clientes_destinos[i]=-1; descriptores_servicios[i]=-1; tiempo_final[i]=0; buff[i][0]=’\0’; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); for(;;){ rset=allset; tv.tv_sec=0; tv.tv_usec=100000; //Discretización 1 décima de segundo nready=select (maxfd+1, &rset, NULL,NULL,&tv); //Bloqueo en espera de entradas if (nready==0){ //Salida de Timeout, if(maxi<0){ // Si no hay clientes no hay que hacer nada, ni siquiera contar, se está en espera. contador=0; break; } contador++; //Ha pasado 1 décima }; //Ahora la conexiones de clientes if ( FD_ISSET(listenfd, &rset)){ //USUARIO NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario for (i=0; i<N; i++) //Actualización del array if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; // Los operarios van después de las líneas if (i>maxi) maxi=i; if (--nready<=0) continue; //Previsión para más de una interrupción } José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 49 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes // En esta parte se leen los nombres de las aplicaciones. for (j=0; j<N; j++){ if ((sockfd1 =client[j])<0) // Se van a comprobar todas los clientes continue; if (FD_ISSET(sockfd1, &rset)) //Se recibe algo if((len=read(sockfd1, msg_rec, MSG_SIZE))> 0){ //Se lee. No es vacío //Hay que extraer el valor XX if ((msg_rec[len-2] != ‘1’) && (msg_rec[len-2] != ‘2’)) //Se ve si el penúltimo dígito es 1 ó 2: numero =atoi (msg_rec[len-1]); else numero = atoi (msg_rec[len-2]); //Si hay que considerarlo. if (aplicaciones[numero]<0){ //NO ESTÁ OCUPADO (Si lo está no se pide solución) if ((descriptores_servicios[numero]=socket(AF_INET, SOCK_STREAM, 0))<= 0) { printf ("ERROR \n"); exit(1); } servaddr.sin_port=htons(APLICACION_LECTURA00+numero); //IMPORTANTE PARA CONECTARSE if ((connect (descriptores_aplicaciones[numero], (struct sockaddr*)&servaddr, sizeof(struct sockaddr))<0){ printf ("ERROR \n"); exit(1); } //No se dice si las aplicaciones son concurrentes o no //La aplicación ya está conectada, actualizamos variables. FD _SET(descriptores_aplicaciones[numero],&allset); if (descriptores_aplicaciones[numero]>maxfd) maxfd = descriptores_aplicaciones[numero]; //Preparado select para escuchar clientes_destino[numero]=client[i]; //Para las operaciones relacionales. //TIEMPOS tiempo_comienzo[numero]=contador; tiempo_final[numero]=0; //Inicializacion tiempo }else{ //Cierre del cliente }; //NO SE PIDE } } } for (j=0; j<M; j++){ if ((sockfd1 =descriptores_aplicaciones[j])<0) // Se van a comprobar todas las aplicaciones continue; if (FD_ISSET(sockfd1, &rset)) { //Se recibe algo -> COMPUTAR TIEMPO José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 50 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if((len=read(sockfd1, buff, MSG_SIZE))> 0){ //Se lee. No es vacío valor=strlen(buff); strncat(buff[i],msg_rec, valor)); if ((valor+strlen(msg_rec))=>MSG_SIZE){ write(clientes_destino[j], buff, strlen(msg_rec)); if (tiempo_final[j]==0){ //Hay que hacer calculo temporal tiempo_final[j]= contador; if (--nready<=0) continue; else break; } retardo=tiempo_final[j]-tiempo_inicial[j]; write(clientes_destino[j],&retardo,strlen(retardo)); if (--nready<=0) continue; } //Previsión para más de una interrupción } } } } //FIN del bucle principal for } //FIN del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 51 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Problema 2 (50% Ejercicios) Se pretende realizar un programa test de un servidor concurrente TCP que es un repositorio de logins y passwords (un repositorio de identidades). El servidor consiste en que recibido un login indica si ese usuario existe y en su caso indica si el password recibido es correcto o no (acepta un formato de mensajes: “login:password”). La respuesta del servidor puede ser “OK”, “DESCONOCIDO” (no se conoce el login) o “FALLO” (fallo del password) y a continuación se cierra la conexión. El test consiste en (1) comprobar el funcionamiento del servidor (responde a logins y passwords de manera adecuada), (2) se pueden realizar un número de conexiones elevado simultáneas como todo servidor concurrente, y (3) comprobar el retardo que ofrece el servidor al cliente. Para ser más precisos se supone que la aplicación test y el servidor operan en la misma máquina. El test necesita una identidad de prueba veraz para poder realizar el test, supóngase que se reciben login y password como argumentos 1 y 2 de la línea de comando respectivamente. Se pide: A) Realice el código necesario para realizar la comprobación (1). Se trata pues de acceder, y hacer dos peticiones una que se supone correcta y otra que no. La comprobación consistirá en ver que efectivamente se recibe “OK” y otro valor en el segundo caso. Para la primera petición se utilizará el login y password leído de la línea de comando, y para la segunda otra combinación aleatoria para login y password de 6 caracteres cada uno. Atiéndalos de forma concurrente. En caso de error se muestra por pantalla “ERROR 1” y se continúa el test. (15%) B) Realice el código necesario para realizar la comprobación (2). Se realiza, utilizando el número máximo de sockets creables (no suponga restricciones del sistema operativo), de realizar conexiones con el servidor, de forma que aproximadamente el 50% pida autorización positiva y el 50% negativas. Atiéndalos de forma concurrente. Se comprobará que efectivamente no quede ningún socket abierto pasados 10 minutos desde la última respuesta recibida. En caso de error se muestra por pantalla “ERROR 2”. (25%) C) Por último, realice el código necesario para realizar la comprobación (3). Modifique el código del apartado B para que se pueda calcular el tiempo que tarda cada servicio (se admite un error tolerable de 0,1 segundos). Conforme se reciban las respuestas se va calculando la media y se muestra por pantalla. (10%) Otra información: #define MSG_SIZE 33 //Tamaño máximo de los mensajes #define servidor_port 5000 //Puerto de funcionamiento del servidor NOTA IMPORTANTE PARA LOS DOS PROBLEMAS: 1.- NO es necesario incluir las macros y librerías habituales en el código de la solución. #define MSG_SIZE 33 //Tamaño máximo de los mensajes #define servidor_port 6200 //Puerto de funcionamiento del servidor #define N FD_SETSIZE-3 // N=número de clientes según apartado B es el máximo menos 3. int main (int argc, char *argv[]){ int maxfd, sockfd1, i ,j, k, contador, contadorC; ssize_t len; fd_set rset, allset; char msg_rec[MSG_SIZE]; // Mensajes recibidos char buff[13]; //Para la gestión de login y passwords aleatorios char* msg_envA ; socklen_t clilen; struct sockaddr_in servaddr; time *s; int cerrrados=0; struct timeval tv; //La variable temporal de 10 segundos José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 52 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes int abiertos; int retardomedio=0; FD_ZERO(&rset); bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (“127.0.0.1”); servaddr.sin_port=htons(servidor_port); maxfd=-1 ; //Se utilizan los datos de entrada para generar un mensaje de petición char* user=strdup(arg[1]); char* user_pass=strdup(arg[2]); char* msg_envA=strcat(user, “:”); msg_env=strcat(msg_envA, user_pass); msg_rec[0]=’\0’; msg_rec_old[0]=’\0’; abiertos=0; FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); //Se deben generar N clients (para el apartado A dos son suficientes) for (i=0; i=N; i++){ //NECESARIO APARTADO B if ((sockfd[i] = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } connect(sockfd[i], (struct sockaddr*) &sevaddr, sizeof(struct sockaddr)); // Siendo una aplicación que utiliza un servicio (un cliente), no se realiza la funcion bind. if (i%2==0){ //Los pares se toman como correctos (50%) if(write(sockfd[i], msg_env, strlen(msg_envA))<0) { printf("ERROR \n"); exit (1); }; }else{ //los impares serán aleatorios srand(time(s)/2); // Se pone la semilla for (j=0; j=13; j++) if(j==6) buff[j]=’:’; else { valor=atoi(a)+rand()%26; buff[j]=char(valor); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 53 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } if(write(sockfd[i], buff, strlen(buff))<0) { printf("ERROR \n"); exit (1); }; } FD_SET(sockfd[i],&allset); //Socket hay que activarlo, pues espera algo. if(listenfd >maxfd) maxfd= listenfd; if (i>maxi) maxi=i; }; contador=0; for(;;){ rset=allset; tv.tv_sec=600; //Tiempo de 600 segundos (diez minutos) tv.tv_usec=0; //Para el apartado (C) tv.tv_sec=0; //Tiempo de 600 segundos son 6000 décimas. tv.tv_usec=1000; nready=select (maxfd+1, &rset, NULL,NULL,&tv); //Bloqueo en espera de entradas //TIME-calculo de tiempo para retardo. Apartado C. if (nready==0){ //Salida de Timeout, contadorC++; contador++; if (contador==6000) if(maxi<0){ // Si no hay clientes se ha hecho bien. exit(1); } //No se indica qué realizar, parece que se puede terminar el test else printf(“ERROR 2\n”); //CASO DE ERROR 2 } }else { //Se lee valor for (j=0; j<N; j++){ //Para apartado B if ((sockfd1 =sockfd[j])<0) // Se van a comprobar todas las aplicaciones continue; if (FD_ISSET(sockfd1, &rset)) { if((len=read(sockfd1, buff, MSG_SIZE))> 0){ //Se lee. //Se realiza la comprobación 1 if ((j%2)==0) //Debería ser OK if (strcmp(buff, “OK”)!=0) printf (“ERROR 1\n”); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 54 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes else //Debería ser algún tipo de error if (strcmp(buff, “OK”)==0) printf (“ERROR 1\n”); retardomedio=(retardomedio*cerrados+contadorC)/(cerrados+1) printf(“El retardo ha sido %d segundos y %d décimas de segundos\n”, retardomedio/10, retardomedio%10); cerrados++; contador==0; if (j==maxi) while(sockfd[maxi]>0) maxi--; if (sockfd1==maxfd) maxfd--; FD_CLR(sockfd1, &allset); continue; } } } //Fin for }//Fin main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 55 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 30 DE JUNIO DE 2009 Problema 1 (50% Ejercicios) Se diseña un servicio TCP concurrente temporizado en el que el los clientes se conectan a este servicio para descargarse información de unos archivos propios del servicio, pero con un tiempo límite de descarga, para asegurar que la copia descargada es la versión correcta, ya que pasado ese tiempo es posible que sean actualizados. El gráfico representa las conexiones de las aplicaciones: Entre las tareas del servicio, se encuentran: − Gestionar las conexiones permanentes con los clientes. Éstos se conectan cuando desean acceder a un archivo. Habrá un total de N conexiones de este tipo en el servidor. − Gestionar la conexión con las aplicaciones de lectura (independientes de la aplicación servidor) que leen el contenido de los archivos (o ficheros). Éstas son conectadas cuando un cliente pide el contenido del archivo que estas leen. − Gestionar la descarga del fichero por el cliente. Se pide: A) Código de aceptación de conexiones de los clientes y lectura del nombre del archivo a enviar por parte del servicio, que se transmite en el primer mensaje que llega del cliente. No olvide realizar el proceso de forma concurrente, utilizando un único select. (20%) B) Código para la lectura de archivos y envío concurrente de su contenido. Una vez el servicio recibe el nombre del archivo, se procede a la conexión con la aplicación de lectura y se transmite su contenido de forma concurrente con mensajes de tamaño máximo. Para saber qué aplicación ha de vincularse, el nombre del archivo lleva un número en su nombre según formato: “nombreXX” que indica el número de aplicación que lee ese contenido. Se mantendrá el uso de un único select. (15%) C) Código para componer la temporización del tiempo válido de descarga de los archivos, que dependerá del tamaño que tenga cada uno. Para ello discretize el tiempo por una décima de segundo y obtenga el instante de comienzo de lectura de cada archivo. Una vez abierto el archivo, obtenga el tamaño del archivo, que suponga se lee en la primera lectura de la aplicación, y calcule el tiempo máximo para su descarga tomando valor de velocidad 300Kbps. Si no se ha completado la transmisión en ese tiempo se reinicia el proceso de transmisión. Suponga que la operación de lectura y transmisión de un paquete es de una centésima de segundo y los demás retardos de código son despreciables. (15%) #define N 20 //dato #define LISTENQ N // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N a la vez. #define SERVER_PORT 2399 //Dato #define APLICACION_LECTURA00 3500 José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 56 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes #define SERVIDOR “192.168.3.254” #define MSG_SIZE 256 //Tamaños maximos int main (int argc, char **argv) { int i, j, maxi, maxfd, listenfd, connfd, sockfd1, nready, numero, valor; int client [N]; // Array de descriptores de los usuario int descriptores_servicios[M]; //Se crea un array de “descriptores locales” para los servicios. // char *aplicaciones[M]; Nombres de aplicaciones. No hace falta guardarlos. int relaciones[N]; //Array de relaciones de clientes, para relacionar cliente->aplicacion int clientes_destinos[M]; // Como para el apartado C hay que relacionar directamente todo, se hace un segundo // array de relaciones aplicación->cliente long tiempo_final[N]; //Para el cálculo del tiempo_final de transmisión long tiempo_comienzo[N[; //Guardar tiempo de apertura del servicio ssize_t len; buff[N][256]; fd_set rset, allset; char msg_rec[MSG_SIZE]; // Mensaje recibido socklen_t clilen; struct sockaddr_in cliaddr, servaddr; struct timeval tv; //Arranque del servidor concurrente if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. maxfd=listenfd; maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; clientes_destinos[i]=-1; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 57 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes descriptores_servicios[i]=-1; tiempo_final[i]=0; buff[i][0]=’\0’; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); for(;;){ rset=allset; tv.tv_sec=0; tv.tv_sec=100000; //Discretización 1 décima de segundo nready=select (maxfd+1, &rset, NULL,NULL,&tv); //Bloqueo en espera de entradas //TIMEOUT if (nready==0){ //Salida de Timeout, if(maxi<0){ // SI no hay clientes no hay que hacer nada, ni siquiera contar, se está en espera. contador=0; break; } contador=contador+10; //Ha pasado 1 décima que son 10 centésimas }; //Ahora la conexiones de clientes if ( FD_ISSET(listenfd, &rset){ //USUARIO NUEVO +TIEMPO DESPRECIABLE clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario for (i=0; i<N; i++) //Actualización del array if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; // Los operarios van después de las líneas if (i>maxi) maxi=i; if (--nready<=0) continue; //Previsión para más de una interrupción } // En esta parte se leen los nombres de las aplicaciones. for (j=0; j<N; j++){ if ((sockfd1 =client[j])<0) // Se van a comprobar todas los clientes José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 58 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes continue; if (FD_ISSET(sockfd1, &rset)) //Se recibe algo +TIEMPO DESPRECIABLE if((len=read(sockfd1, msg_rec, MSG_SIZE))> 0){ //Se lee. No es vacío if (relaciones[N]<0) { //Es el primer mensaje… luego nos interesa el número de puerto //Hay que extraer el valor XX if ((msg_rec[len-2] != ‘1’) && (msg_rec[len-2] != ‘2’)) //Se ve si el penúltimo dígito es 1 ó 2: numero =atoi (msg_rec[len-1]); else numero = atoi (msg_rec[len-2]); //Si hay que considerarlo. //Ahora se pasa a establecer servicio con la aplicación, el “numero” calculado es muy práctico… if (descriptores_servicios[numero]<0){ //NO ESTÁ OCUPADO (Si lo está no se pide solución) if ((descriptores_servicios[numero]=socket(AF_INET, SOCK_STREAM, 0))<= 0) { printf ("ERROR \n"); exit(1); } servaddr.sin_port=htons(APLICACION_LECTURA00 +numero); //IMPORTANTE PARA CONECTARSE if ((connect (descriptores_servicios[numero], (struct sockaddr*)&servaddr, sizeof(struct sockaddr))<0){ printf ("ERROR \n"); exit(1); } //No se dice si las aplicaciones son concurrentes o no //La aplicación ya está conectada, actualizamos variables. FD_SET(descriptores_servicios [numero],&allset); if (descriptores_servicios[numero]>maxfd) maxfd = descriptores_servicios[numero]; //Preparado select para escuchar relaciones[i]=descriptores_servicios[numero]; //Luego para las respuestas clientes_destino[numero]=client[i]; //Para las operaciones relacionales. //TIEMPOS tiempo_comienzo[numero]=contador; tiempo_final[numero]=0; } else //CUANDO SE RECIBAN DATOS DEL CLIENTE. NO SE PIDE {} }else //Cierre del cliente { }; //NO SE PIDE } } for (j=0; j<M; j++){ if ((sockfd1 =descriptores_aplicaciones[j])<0) // Se van a comprobar todas las aplicaciones continue; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 59 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if (FD_ISSET(sockfd1, &rset)) { //Se recibe algo -> COMPUTAR TIEMPO if((len=read(sockfd1, msg_rec, MSG_SIZE))> 0){ //Se lee. No es vacío if (tiempo_final[j]==0){ //Es el tamaño tiempo_final[j]= contador+(int) (8*atoi(msg_rec)/3000); if (--nready<=0) continue; else break; } if (tiempo_final[j]<contador){ valor=strlen(buff[i]); strncat(buff[i],msg_rec,MSG_SIZE-valor)); if ((valor+strlen(msg_rec))=>MSG_SIZE){ //Si al añadir sobrepasamos el tamaño max. write(clientes_destino[j], buff[i], strlen(msg_rec)); strcpy(buff[i], msg_rec[MSG-SIZE-valor-1]); buff[i][MSG-SIZE-valor]=’\0’; } contador++; } }else{ FD_CLR(sockfd1, &allset); close(sockfd1); } if ((descriptores_servicios[numero]=socket(AF_INET, SOCK_STREAM, 0))<= 0) { printf ("ERROR \n"); exit(1); } FD_SET (descriptores_servicios[numero], &allset); servaddr.sin_port=htons(APLICACION_LECTURA00 +j); //IMPORTANTE PARA CONECTARSE if ((connect (descriptores_servicios[numero], (struct sockaddr*)&servaddr, sizeof(struct sockaddr))<0){ printf ("ERROR \n"); exit(1); } //La aplicación ya está nuevamente conectada… faltan los tiempos. tiempo_comienzo[numero]=contador; tiempo_final[numero]=0; if (--nready<=0) continue; } //Previsión para más de una interrupción } } //FIN del bucle principal for José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 60 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } //FIN del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 61 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Problema 2 (50% Ejercicios) Se pretende realizar una aplicación de encaminamiento en una red datagrama (sin conexión) que se encarga de reenviar, según las indicaciones de un algoritmo, los paquetes que le llegan por cada entrada, hacia una salida determinada (que puede ser otra aplicación cómo esta o un destino definitivo). Como existen todo tipo de aplicaciones y por tanto muchos servicios en la red, es necesario abrir un conjunto (se dimensiona desde el 2000 al 2099) de puertos para asegurar que un paquete no se pierde mientras la aplicación calcula la salida de otro paquete. Se pide: A) Realice el código necesario para que la aplicación sea capaz de abrir los 100 puertos que se solicitan para esta aplicación y atender simultáneamente las entradas (leer los paquetes) que se pueden producir por cada uno de ello. Realícelo de forma concurrente y utilice un único select para esta aplicación. (20%) B) Realice el código para que la aplicación sea capaz de enviar la información leída a un destino determinado, de forma concurrente. Para ello utilice una función que calcula el algoritmo de encaminamiento: struct sockaddr *routing(struct sockaddr *origen destino). Envíe la información por la salida determinada por la mencionada función. (10%) C) Por último, suponga ahora el servicio se adapta al entorno de manera que cuando la tasa de llegada de paquetes es elevada y, por ello, la aplicación no puede esperar a que se ejecute la función routing, que es bastante lenta. Para ello: C.1) Detecte la saturación mediante un temporizador en select de una décima de segundo. Cuando se ejecute select 100 veces seguidas sin expirar el timer suponga saturación. (10%) C.2) En caso de saturación se generará un servicio multiprocesado concurrente, asignando un único puerto a cada nuevo proceso. Estos nuevos procesos realizarán el servicio tal y como estaba diseñado. (10%). Otra información: #define MSG_SIZE 1024 //Tamaño máximo de los mensajes #define Direccion_local “192.168.3.1” NOTA IMPORTANTE PARA LOS DOS PROBLEMAS: 1.- NO es necesario incluir las macros y librerías habituales en el código de la solución. #define MSG_SIZE 1024 //Tamaño máximo de los mensajes #define Direccion_local “192.168.3.1” #define PUERTO_ORIGEN 2000 int main (int argc, char **argv) { int maxfd, listenfd, i ,j, k; int contador; ssize_t len; fd_set rset, allset; char msg_rec[MSG_SIZE]; // Mensajes recibidos socklen_t clilen; int client[100]; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 62 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes struct sockaddr_in servaddr, cliaddr, *destaddr; struct timeval tv; //La variable temporal de 1 decima segundo int multiprocesado=0; // Para solo hacerlo una vez //Se abre el servicio //Hay que abrir 100 puertos. Al ser UDP, no se requiere conexión, no hay bloqueo asíncrono, por lo que se puede //proceder a hacerlo directamente en “bucle”. FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (Direccion_local); maxfd=-1 ; for (i=0 ; i<=99 ;i++) { if ((client[i] = socket(AF_INET,SOCK_DGRAM,0))<= 0) { printf ("ERROR \n"); exit(1); } servaddr.sin_port=htons(PUERTO_ORIGEN+i); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))<0) { printf("ERROR \n"); exit (1); }; FD_SET(client[i],&allset); //Socket hay que activarlo if(client[i]>maxfd) maxfd=client[i]; }; //Aplicación UDP preparada msg_rec[0]=’\0’; for(;;){ rset=allset; tv.tv_sec=0; tv.tv_usec=100000; nready=select (maxfd+1, &rset, NULL, NULL, &tv); //Bloqueo en espera de entradas o timeout if (nready==0){ //Salta timeout contador=0; continue; } for (j=0; j<M; j++){ if ((sockfd1 =client[j])<0) // Se van a comprobar todas las entradas José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 63 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes continue; if (FD_ISSET(sockfd1, &rset)) { //Se recibe algo -> COMPUTAR TIEMPO EN CONTADOR contador++; if ((contador>=100) && !multiprocesado){//Condición de salto… Se necesita generación multiproceso. for (j=0; j<99, j++){ //Hay que generar 99 hijos, el padre se hará cargo de un puerto. multiprocesado=1; if (fork()==0){ //UN HIJO //Se le asigna por ejemplo, el descriptor del puerto j, por tanto el resto hay que cerrarlo. for (k=99; k>0; k--) if (k!=j){ FD_CLR(client[k], &allset); if (client[k]==maxfd) maxfd--; client[k]=-1; } //El hijo se quedaría con un select y sólo un puerto el j-ésimo atento break; //Y en el hijo no hay que hacer nada más. } }else { //Y el padre debe cerrar el puerto tomado por el hijo FD_CLR(client[j], &allset); if (client[j]==maxfd) maxfd--; client[j]=-1; }; // El padre ha de seguir iterando para generar hijos }; if((len=recvfrom(sockfd1, msg_rec, MSG_SIZE, 0, (struct sockaddr*)&cliaddr, &clilen))> 0){ //Se lee. No es vacío //APLICACIÓN SERVICIO (APARTADO B) msg_rec[len]=’\0’; destaddr= (struct sockaddr_in*) routing((struct sockaddr*)&cliaddr); //Según indica el enunciado esta funcion //devuelve el destino a donde hay que reenviar. //Es una función interna, por lo que no se puede multiplexar. //Y se envía por ejemplo por el mismo puerto que llegó. sendto(sockfd1, msg_rec, strlen(msg_rec),0, (struct sockaddr *)destaddr, sizeof(struct sockaddr)); }; }//Fin del for de atención a puertos }//FIN bucle principal } //Fin del MAIN José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 64 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 12 DE SEPTIEMBRE DE 2008 Problema 1 (50% Ejercicios) Se diseña un servicio TCP concurrente en el que el los clientes se conectan para acceder a información que están generando aplicaciones que corren de manera autónoma en la misma máquina en el que se ejecuta el servicio. El gráfico representa las conexiones de las aplicaciones: Entre las tareas del servicio, se encuentran: − Gestionar las conexiones permanentes con los clientes. Éstos se conectan cuando desean acceder a una aplicación. Habrá un total de N conexiones de este tipo en el servidor. − Gestionar las conexiones permanentes con las aplicaciones (actúan como servicio). Éstas son conectadas por el servidor en el momento detallado en la cuestión B. Habrá un total de M conexiones de este tipo. − Gestionar la comunicación cliente-aplicación. Se pide: A) Código para aceptar la conexión de clientes. Éstos se conectan al servidor que les debe proporcionar servicio. En el primer mensaje, el cliente invoca la aplicación deseada con su nombre. Recuerde utilizar un solo select para todo el ejercicio. (10%) B) Código para conectarse con las aplicaciones. Estas operan como servicios TCP en los puertos [3100..310M]. El proceso de conexión se produce cuando algún cliente solicita la aplicación que se menciona. Para relacionar aplicación con el puerto, el nombre de cada una lleva incluido el número M en él con formato “nombreM”. El puerto de la aplicación es por tanto 3100+M. Una vez conectada, el servidor no se desconecta de la aplicación hasta que el cliente se desconecta de él. (25%) C) Código para preparar la comunicación cliente-aplicación. Con el nombre capturado, y el descriptor de la conexión se trata de relacionar de manera directa cliente y aplicación (p. ej. uno/dos arrays), de forma que lo que llegue por uno se pueda propagar al otro sin más cálculos. Indique en el código dónde se debe incluir dicha propagación de mensajes. (15%) Otra información: #define N 20 #define M 29 #define SERVIDOR “192.168.5.254” #define SERVER_PORT 2399 #define MSG_SIZE 256 // Tamaño maximo para los nicks, datos del juego y nicks+struct_sockaddr. #define N 20 //dato #define M 29 //dato #define LISTENQ N // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N a la vez. #define SERVER_PORT 2399 //Dato #define SERVICIOS 3100// A partir de este están todos los servicios José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 65 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes #define SERVIDOR “192.168.5.254” #define MSG_SIZE 256 //Tamaños maximos int main (int argc, char **argv) { int i, j, maxi, maxfd, listenfd, resto, connfd, sockfd1, nready, numero, valor; int client [N]; // Array de descriptores de los usuario int descriptores_servicios[M]; //Se crea un array de “descriptores locales” para los servicios. // char * aplicaciones[M]; Nombres de aplicaciones. No hace falta guardarlos. int relaciones[N]; //Array de relaciones de clientes, para relacionar cliente->aplicacion int clientes_destinos[M]; // Como para el apartado C hay que relacionar directamente todo, se hace un segundo // array de relaciones aplicación->cliente ssize_t len; fd_set rset, allset; char msg_rec[MSG_SIZE]; // Mensaje recibido socklen_t clilen; struct sockaddr_in cliaddr, servaddr; //Arranque del servidor concurrente if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. maxfd=listenfd; maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; relaciones[i]=-1; } for (i=0; i<M;i++){ //Hay dos arrays distintos clientes_destinos[i]=-1; descriptores_servicios [i]=-1; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 66 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); //Ahora no hay que inicializarlo for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas //Ahora la conexiones de clientes if ( FD_ISSET(listenfd, &rset){ //USUARIO NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario for (i=0; i<N; i++) //Actualización del array if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; // Los operarios van después de las líneas if (i>maxi) maxi=i; if (--nready<=0) continue; //Previsión para más de una interrupción } for (j=0; j<N; j++){ if ((sockfd1 =client[j])<0) // Se van a comprobar todas los clientes continue; if (FD_ISSET(sockfd1, &rset)) //Se recibe algo if((len=read(sockfd1, msg_rec, MSG_SIZE))> 0){ //Se lee. No es vacío if (relaciones[N]<0) { //Es el primer mensaje… luego nos interesa el número de puerto //Hay que extraer el valor M… valor=atoi(msg_rec[len-2]); if ((valor != 1) || (valor != 2)) //Se ve si el penúltimo dígito es 1 ó 2: numero =atoi (msg_rec[len-1]); else numero = 10*valor+ atoi (msg_rec[len-1]); //Si hay que considerarlo. //Ahora se pasa a establecer servicio con la aplicación, el “numero” calculado es muy práctico… José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 67 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if (aplicaciones[numero]<0){ //NO ESTÁ OCUPADO (Si lo está no se pide solución) if ((descriptores_servicios[numero]=socket(AF_INET, SOCK_STREAM, 0))<= 0) { printf ("ERROR \n"); exit(1); } servaddr.sin_port=htons(SERVICIOS+numero); //IMPORTANTE PARA CONECTARSE if ((connect (descriptores_servicios[numero], (struct sockaddr*)&servaddr, sizeof(struct sockaddr))<0){ printf ("ERROR \n"); exit(1); } //La aplicación ya está conectada, actualizamos variables. FD _SET(descriptores_servicios [numero],&allset); if (descriptores_servicios[numero]>maxfd) maxfd = descriptores_servicios[numero]; //Preparado select para escuchar relaciones[i]=descriptores_servicios[numero]; //Luego para las relaciones apartado C clientes_destino[numero]=client[i]; //Para las operaciones relacionales. }else //CUANDO SE RECIBAN DATOS. NO SE PIDE { } } //Fin del if entrada de datos else //Cierre del cliente //Es cerrar dos conexiones a la vez… close (sockfd1); //Cliente close(relaciones[i]); //Aplicación relacionada //Y se actualizan variables j=0; while (client[i]!=cliente_destino[j]) j++; if (j<M){ //Encontrada la aplicación FD_CLR(client[i], &allset); FD_CLR(aplicaciones[j],&allset); //Conjuntos de descriptores if (aplicaciones[i]==maxfd) maxfd--; //maxfd client[i]=-1; cliente_destino[j]=-1; relaciones[i]=-1; aplicaciones[j]=-1; //arrays actualizados if (i==maxi) maxi--; //maxi }else{ printf(“error/n”); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 68 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } if (--nready<=0) break; } } for (j=0; j<M; j++){ if ((sockfd1 =descriptores_aplicaciones[j])<0) // Se van a comprobar todas las aplicaciones continue; if (FD_ISSET(sockfd1, &rset)) //Se recibe algo if (--nready<=0) continue; //Previsión para más de una interrupción } //CÓDIGO APARTADO B } //FIN del bucle principal for } //FIN del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 69 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Problema 2 (50% Ejercicios) Se pretende realizar una aplicación distribuida en una red local en la que los distintos equipos que la conforman puedan transmitirse entre ellas información del propio sistema al resto de equipos, para que tomen decisiones sobre rendimiento, tasas de transmisión, etc. (las decisiones a considerar no se piden en este ejercicio). La aplicación es única, es decir, la misma aplicación se encarga de leer los datos del sistema y mandarlos al resto de equipos y de recibir los datos de los otros equipos y guardarlos. Se pide: A) Realice el código necesario para que el equipo sea capaz de leer los datos de funcionamiento interno del equipo. Estos datos se releen regularmente cada segundo o cada ver que se reciben datos del resto de equipos (código del apartado C). La lectura se realiza sobre una serie de 10 archivos denominados “datosX.dat”, (X es un número entre 0 y 9), que se actualizan solidariamente. (20%) B) Realice el código para transmitir los datos leídos al resto de equipos. La transmisión se produce cada vez que se realiza la lectura de datos, sea cuál sea el momento, y en un solo mensaje individual para cada equipo de la red (UNICAST), excepto él mismo claro. El mensajes es composición de los datos leídos del apartado A concatenados uno detrás de otro en orden X y separados por el símbolo “:”. (15%) C) Por último, la misma aplicación es capaz de recibir datos de la aplicación que se ejecute en otro equipo. Prepare la aplicación para ello y con la información de llegada (mismo formato que apartado B) guárdela sin modificar en una serie de archivos “salidaY.dat” donde Y es el número de equipo de donde viene la información, que coincide con el último dígito de su IP. (15%) Otra información: #define EQUIPOS 8 //Número de equipos de la red local #define MSG_SIZE 1024 //Tamaño máximo de los mensajes #define APPLICATION_PORT 5200 // Puerto de la aplicación #define DATO_SIZE 8 //Tamaño máximo de cada uno de los datos a leer #define Direccion_local “192.168.3.1” Nota: La máscara de red es 255.255.255.254. Suponga que las direcciones ocupadas son las menores posibles: 1, 2,… EQUIPOS. #define EQUIPOS 8 //Número de equipos de la red local #define MSG_SIZE 1024 //Tamaño máximo de los mensajes #define APPLICATION_PORT 5200 // Puerto de la aplicación #define DATO_SIZE 8 //Tamaño máximo de cada uno de los datos a leer #define Direccion_local “192.168.3.1” int main (int argc, char **argv) { int maxfd, listenfd; int X, Y; char *nombre, *leido, *aux, *aux2; char *direccion, *ip_grupo; ssize_t len; fd_set rset, allset; char * msg_env; //Mensaje enviado char msg_rec[MSG_SIZE]; // Mensajes recibidos José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 70 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes socklen_t clilen; FILE *fl; struct sockaddr_in servaddr, cliaddr; struct timeval tv; //La variable temporal de 1 segundo //Se abre el servicio if ((listenfd = socket(AF_INET,SOCK_DGRAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (Direccion_local); servaddr.sin_port=htons(APPLICATION_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))<0) { printf("ERROR \n"); exit (1); } //La operación bind hay que hacerla para que asegurar la utilización del puerto 5200, y para poder recibir datos en el // apartado C. //Aplicación UDP preparada numero=0; msg_rec1[0]=’\0’; msg_rec2[0]=’\0’; FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); //Socket hay que activarlo //Se puede hacer la primera lectura y tx ahora. El código es repetido para el caso genérico. msg_env=NULL; for (X=0; X<=9; X++){ nombre=NULL; //Inicialiazion del nombre del archive. nombre=strcat(“dato”, (char *) X); //Como X es menor de 256 se puede hacer casting sin perder nada nombre=strcat(nombre, “.dat·”); fl=fopen(nombre, “r”) ; fgets(leido, DATO_SIZE, fl) ; // Se leen los datos (una sóla lectura de 8 bytes) fclose(fl) ; msg_env=strcat(msg_env, leido); if (X!=9) msg_env=strcat(msg_env,”:”); //El mensaje está listo }; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 71 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes //Mecanismo para sacar la dirección IP de los destinos ipgrupo=strdup(Direccion_local); aux=ipgrupo; for (i=0; i<strlen(ip_agrupo); i++) aux++; aux=`’\0’; //Se coge la dirección menos el último carácter [1..8]. //La dirección IP de los equipos esta guardad en ip_grupo. for (Y=1, Y<=EQUIPOS; Y++){ aux2= strcat(ipgrupo, (char *)Y); //Se forma direccion destino servaddr.sin_addr.s_addr=inet_addr(aux2); if (strcmp(aux2, Direccion_local)) //Control para no enviar a sí mismo sendto(listenfd, msg_env, strlen(msg_env), 0, (struct sockaddr*) &servaddr, sizeof(struct sockaddr)); } for(;;){ rset=allset; tv.tv_sec=1; tv.tv_usec=0; nready=select (maxfd+1, &rset, NULL, NULL, &tv); //Bloqueo en espera de entradas o timeout if ( FD_ISSET(listenfd, &rset){ //SOCKET len=recvfrom(listenfd, msg_env, strlen(msg_env), 0, (struct sockaddr*) &cliaddr, &clilen); direccion=inet_ntoa(&cliddr.sin_addr.s_addr); //Se saca la dirección del remitente aux=direccion; //Se pueden reusar variables for (i=0; i<strlen(ip_agrupo);i++) {aux++;} // Se obtiene el último caracter para el nombre del archivo nombre=strcat(“salida”, aux); nombre=strcat(nombre, “.dat·”); //Se forma el nombre fl=fopen(nombre, “w”) ; //Se abre archivo fputs(msg_rec, DATO_SIZE, fl) ; //Se escribe lo recibido fclose(fl) ; // Se cierra archivo } //SIEMPRE QUE SE SALGA POR SELECT SE TRANSMITE LUEGO SE PONE SIN NECESIDAD DE HACER // FD_ISSET msg_env=NULL; for (X=0; X<=9; X++){ nombre=NULL; //Inicialiazion del nombre del archive. nombre=strcat(“dato”, (char *) X); //Como X es menor de 256 se puede hacer casting sin perder nada nombre=strcat(nombre, “.dat·”); fl=fopen(nombre, “r”) ; fgets(leido, DATO_SIZE, fl) ; // Se leen los datos (una sóla lectura de 8 bytes) José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 72 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes fclose(fl) ; msg_env=strcat(msg_env, leido); if (X!=9) msg_env=strcat(msg_env,”:”); //El mensaje está listo }; //Mecanismo para sacer la dirección IP de los destinos ip_grupo=strdup(Direccion_local); aux=ipgrupo; for (i=0; i<strlen(ip_agrupo); i++) aux++; aux=`’\0’; //Se coge la dirección menos el último carácter [1..8]. //La dirección IP de los equipos esta guardad en ip_grupo. for (Y=1, Y<=EQUIPOS; Y++){ aux2= strcat(ipgrupo, (char *)Y); //Se forma direccion destino servaddr.sin_addr.s_addr=inet_addr(aux2); if (strcmp(aux2, Direccion_local)) //Control para no enviar a sí mismo sendto(listenfd, msg_env, strlen(msg_env), 0, (struct sockaddr*) &servaddr, sizeof(struct sockaddr)); } } //Fin del for } //Fin del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 73 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 01 DE JULIO DE 2008 Problema 1 (50% Ejercicios) Se diseña un servicio TCP concurrente en el que el los clientes se conectan para acceder a información que están generando aplicaciones que corren de manera autónoma en la misma máquina en el que se ejecuta el servidor. El gráfico representa las conexiones de las aplicaciones: Entre las tareas del servicio, se encuentran: − Gestionar las conexiones permanentes con los clientes. Éstos se conectan cuando desean acceder a una aplicación. Habrá un total de N conexiones de este tipo en el servidor. − Gestionar las conexiones permanentes con las aplicaciones (actúan como servicio). Éstas son conectadas por el servidor cuando se arranca el mismo. Habrá un total de M conexiones de este tipo. − Gestionar la comunicación cliente-aplicación. Se pide: A) Código para conectarse con las aplicaciones. Estas operan como servicios TCP en los puertos [3101..310M]. Una vez conectadas las aplicaciones, éstas mandan el nombre de cada aplicación, que se debe guardar en el servidor. Hágalo de manera concurrente. (25%) B) Código para aceptar la conexión de clientes. Una vez las M aplicaciones están activas para la comunicación, se puede pasar a aceptar los N clientes. Éstos se conectan al servidor que les debe proporcionar servicio. Recuerde utilizar un solo select para todo el ejercicio. (12,5%) C) Código para preparar la comunicación cliente-aplicación. El cliente manda el nombre de la aplicación en la que está interesado en su primer mensaje, el servidor lo lee y en un array específico relaciona la conexión del cliente con la de la aplicación. No realice el código de transmisión de mensajes. (12,5%) Otra información: #define N 20 #define SERVIDOR “192.168.5.254” #define SERVER_PORT 2399 #define MSG_SIZE 256 // Tamaño maximo para los mensajes. #define N 20 //Se le da un valor #define M 30 //Se le da otro valor José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 74 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes #define LISTENQ N // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N a la vez. #define SERVER_PORT 2399 //Dato #define SERVICIOS 3101 // A partir de este están todos los servicios #define SERVIDOR “192.168.5.254” #define MSG_SIZE 256 //Tamaños maximos struct clientes { //aunque no se pide, parece interesante crear una estructura para guardar los datos… int sockfd; //puede llevar el descriptor del socket. char * aplicacion; //puede llevar el nombre de la aplicación solicitada int descriptor_aplicacion; //lo más importante será el descriptor de la aplicación }; int main (int argc, char **argv) { int i, j, k, maxi, maxfd, listenfd, resto, connfd, sockfd1, nready, numero, numero_resto; int client [N]; // Array de descriptores de los usuario int descriptores_servicios[M]; //Se crea un array de “descriptores locales” para los servicios. char * aplicaciones[M]; // Array de nombres de aplicaciones. struct clientes relaciones[N]; //Array de estructuras clientes, para relacionar cliente->aplicacion ssize_t len; fd_set rset, allset; char msg_rec[MSG_SIZE]; // Mensaje recibido socklen_t clilen; struct sockaddr_in cliaddr, servaddr; /* Para conectar servicios hay que generar M sockets TCP clientes, cada uno para cada servicio, y hacerlos concurrentes para poder atender la información que mandan cuando se conecta. Se podría denominar “cliente concurrente de servicios TCP”. Se podría resolver haciendo: a) polling… muy apropiado para este funcionamiento. b) Realizar las conexiones iterativas y recibir la información (nombre) de forma concurrente. Más eficiente. c) Select, escalonado-> el fin del establecimiento de la conexión con una aplicación, lanza la de la siguiente. Parece lo más apropiado debido a que son conexiones con la misma máquina y no saturar. d) Simplemente iterativo, uno después de otro, sin utlilizar select-> no es concurrente, peor solución. Como polling no está estudiado explícitamente en este curso, optamos por la forma (c) [(b) es igual de válido y más sencillo de implementar, (d) pierde puntuación] */ //Como va a haber que abrir el puerto de aceptar conexiones de clientes, lo vamos haciendo… //Arranque del servidor concurrente if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 75 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. maxfd=listenfd; maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; relaciones[i].sockfd=-1; relaciones[i].descriptor_aplicacion=-1; relaciones[i]->aplicacion=NULL; } for (i=0; i<M;i++){ //Hay dos arrays distintos aplicaciones[i]=NULL; descriptores_servicios [i]=-1; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); // FD_SET(listenfd, &allset); Ahora no hay que inicializarlo k=0; //UN CONTADOR NECESARIO PARA LLEVAR EL NÚMERO DE APLICACIONES CONECTADAS //Se empiezan a conectar servicios: Se utilizar servaddr ya que está medio configurada. servaddr.sin_port=htons(SERVICIOS); if ((descriptores_servicios[0]=socket(AF_INET, SOCK_STREAM, 0))<= 0) { printf ("ERROR \n"); exit(1); } if ((connect (descriptores_servicios[0], (struct sockaddr*)&servaddr, sizeof(struct sockaddr))<0) { printf ("ERROR \n"); exit(1); } //El primero ya está…. A falta de recibir el nombre. Cuando termine el primero irá al segundo… y así hasta el M. FD_SET(descriptores_servicios [0],&allset); if (descriptores_servicios[0]>maxfd) maxfd = descriptores_servicios[0]; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 76 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes //Preparado select para escuchar for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas for (j=0; j<M; j++){ if ((sockfd1 =aplicaciones[j])<0) // Se van a comprobar todas las aplicaciones continue; if (FD_ISSET(sockfd1, &rset)) //Se recibe el nombre de la aplicación if((len=read(sockfd1, msg_rec, MSG_SIZE))> 0) //Se lee if(strlen(aplicaciones[j]==0)) { // Para posibles futuros usos, se puede preparar… aplicaciones[j]=strdup(msg_rec); // Se guarda el nombre k++; //Uno hecho if (k<M){ //Hay que preparar uno nuevo servaddr.sin_port=htons(SERVICIOS+k); if ((descriptores_servicios[j+1]=socket(AF_INET, SOCK_STREAM, 0))<= 0) { printf ("ERROR \n"); exit(1); } if ((connect (descriptores_servicios[j+1], (struct sockaddr*)&servaddr, sizeof(struct sockaddr))<0){ printf ("ERROR \n"); exit(1); } FD_SET(descriptores_servicios [j+1],&allset); if (descriptores_servicios[j+1]>maxfd) maxfd = descriptores_servicios[j+1]; //Preparado select para escuchar else{ // Cuando se han conectado todos los serv y todos han respondido se puede pasar a los clientes FD_SET(listenfd, &allset); // Y así está preparado para aceptar clientes } } } } } if (--nready<=0) break; } // Fin del for de aplicaciones if ( FD_ISSET(listenfd, &rset){ //USUARIO NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 77 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes for (i=0; i<N; i++){ //Actualización del array if (client[i]<0) { client[i]=connfd; break; } relaciones[i].sockfd=connfd; //Luego para las relaciones apartado C. FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; // Los operarios van después de las líneas if (i>maxi) maxi=i; if (--nready<=0) continue; //Previsión para más de una interrupción } } for (i=0; i<=maxi; i++){ if ((sockfd1 =client[i])<0) // Se van a comprobar todos los usuarios conectados continue; if (FD_ISSET(sockfd1, &rset)){ //Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec,MSG_SIZE))>0){ //El proceso de cierre no se pide… if (strlen(relaciones[i].aplicacion)==0){ //Es el nombre. No tiene nombre guardado. relaciones[i].aplicacion =strdup(msr_rec); j=0; while ((j<=M) && strcmp(msg_rec, aplicaciones[j])) { j++; } //Se busca el nombre de la aplicación. if (j<M) //Se ha encontrado relaciones[i].descriptor_aplicacion= descriptores_servicios[j]; //Se relaciona else write(sockfd1, “SERVICIO NO DISPONIBLE\0”, strlen(“SERVICIO NO DISPONIBLE\0”)); }else{ /* FALTA AÑADIR CÓDIGO DE ATENCIÓN A CLIENTES NO SE PIDE */ } } } //Fin del FD_ISSET if (--nready<=0) continue; } //Previsión para más de una interrupción }Fin del for de clientes }// FIN del bucle principal for }// Fin del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 78 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Problema 2 (50% Ejercicios) Se pretende realizar una aplicación que permita a un usuario mandar datos (texto) de un móvil a otro, tipo servicio SMS. El servicio se realiza sin servidor, directamente se realiza la transmisión de móvil a móvil, por lo que para poder realizar la transmisión es necesario que el destino se encuentre en la misma celda de cobertura, ya que la estación base propaga mensajes a todos lo móviles conectados a él pero no al resto de la red. Es decir, para que se pueda transmitir el mensaje los móviles deben estar cerca, y además la comunicación se realiza sin servidor. Se pide: A) Realice el código necesario de para que el móvil sea capaz de leer primero el número destino y luego el mensaje texto del usuario a través del teclado. Por supuesto, no se puede bloquear el móvil durante la recepción de ambos datos proporcionados por el usuario. Prepare la concurrencia para el resto del ejercicio. (20%) B) Realice el código para que la aplicación, con el número de teléfono, manda un mensaje “broadcast” (IP “192.168.255.255”) conteniendo en el mensaje el número de teléfono solicitado. A continuación, esperará la recepción de un mensaje sin datos que le informa de la dirección IP del destino. Con esa dirección se puede realizar la transmisión del mensaje concreto de texto. Transmita el mensaje de texto con la dirección recibida. Hágalo de forma concurrente y de la forma más ágil posible. (25%) C) Por último, la misma aplicación es capaz de recibir datos en cualquier momento de la misma aplicación de otro móvil. Prepare la aplicación para ello y con la información de texto llegada muéstrela por pantalla. (5%) Otra información: #define MSG_SIZE 1024 //Tamaño máximo de los mensajes #define APPLICATION_PORT 4200 // Puerto de la aplicación #define PUERTO_BROADCAST 5000 //Puerto destino para mandar información broadcast #define Direccion_local “192.168.3.1” Nota: Los número de teléfono posee nueve cifras. #define MSG_SIZE 1024 //Tamaño máximo de los mensajes #define APPLICATION_PORT 4200 // Puerto de la aplicación #define PUERTO_BROADCAST 5000 //Puerto para esperar recibir información broadcast #define Direccion_local “192.168.3.1” #define TECLADO 0 // Descriptor para el teclado int main (int argc, char **argv) { int maxfd, listenfd, mandarya; char numero[9]; ssize_t len; fd_set rset, allset; char * msg_env; //Mensaje enviado de llamada char msg_rec1[MSG_SIZE], msg_rec2[MSG_SIZE]; // Mensaje recibido de teclado socklen_t clilen; struct sockaddr_in servador, cliaddr; mandarya=0; if ((listenfd = socket(AF_INET,SOCK_DGRAM,0))<= 0) { printf ("ERROR \n"); exit(1); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 79 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (Direccion_local); servaddr.sin_port=htons(APLICATION_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))<0) { printf("ERROR \n"); exit (1); } //La operación bind hay que hacerla para que asegurar la utilización del puerto 4200, y para poder recibir datos en el // apartado C. //Aplicación UDP preparada numero[0]=’\0’; msg_rec1[0]=’\0’; msg_rec2[0]=’\0’; if (listenfd>TECLADO) maxfd=listenfd; else maxfd =TECLADO; FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); //Socket hay que activarlo FD_SET(TECLADO, &allset); //Teclado hay que activarlo for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL, NULL, NULL); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset){ //SOCKET { //RECEPCIÓN RESPUESTA BROADCAST. APARTADO B if ((len=recvfrom(listenfd, msg_rec2, MSG_SIZE,0, (struct sockaddr*)&cliaddr,&clilen))== 0){ // Mensaje vacio //respuesta al paquete broadcast //Lo que interesa es la direccion IP del destino. El puerto habrá que actualizarlo. cliaddr.sin_port=htons(APPLICATION_PORT); //Con esta información se puede enviar el mensaje. if (strlen(msg_rec)>0){ // Por si acaso no está todavía escrito sendto (listenfd, msg_rec1, strlen(msg_rec1), 0, (struct sockaddr*)&cliaddr, sizeof(struct sockaddr)); numero [0]=’\0’; }else mandarya=1; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 80 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes else{ // Se reciben datos printf( “%s\n”, msg_rec2); }; } if ( FD_ISSET(TECLADO, &rset){ //USUARIO=TECLADO if(strlen(numero)==0){ //NO se ha recibido todavía el número. fgets(numero, 9, stdin); //Se lee numero msg_rec1=’\0’; // ENVÍO PAQUETE BROADCAST CÓDIGO APARTADO B //Configurar direccion servaddr.sin_addr.s_addr= inet_addr (“192.168.255.255”); servaddr.sin_port=htons(PUERTO_BROADCAST); //Y mandar sendto (listenfd, numero, strlen(numero), 0, (struct sockaddr*)&servaddr, sizeof(struct sockaddr)); }else //SE había leído ya el número fgets(msg_rec1, MSG_SIZE, stdin); if (mandarya) { sendto (listenfd, msg_rec1, strlen(msg_rec1), 0, (struct sockaddr*)&cliaddr, sizeof(struct sockaddr)); mandarya=0;numero[0]=’\0’; } //Caso para optimizar tx (APARTADO B) } } Fin del for 04 DE FEBRERO DE 2007 Problema 1 (60% Ejercicios) Se diseña un servidor concurrente TCP destinado al servicio SSH. El demonio SSHD acepta la conexión de los distintos usuarios y los mantiene conectados mientras no termina la sesión. El gráfico representa el sistema una vez conectados los usuarios: José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 81 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Entre las tareas del servidor, se encuentran: − Gestionar las conexiones permanentes con los usuarios. Éstos se conectan cuando desean establecer una sesión. Habrá un total de N conexiones de este tipo. − Gestionar la lectura de login y password del usuario. Los usuarios sólo pueden enviar tres tipos de paquetes: su conexión, su password y los comandos a ejecutar. − Gestionar la creación de las consolas de ejecución de comandos una vez los usuarios se conectan y su password es correcto. Se pide: A) Código para aceptar la conexión de los usuarios y proporcionar la concurrencia. Gestionar la lectura de los login y password de usuario que son respectivamente el primer y segundo mensaje que se recibe del usuario. Procure proporcionar concurrencia en este proceso. (25%) B) Comprobar y aceptar la autorización de usuario, (con su login y password) mediante la función: int confirma (char * login, char *password). La función devuelve 0 si está autorizado y otro número en cualquier otro caso. En caso de no estar autorizado se cierra la conexión. (15%) C) Gestione la creación de las consolas de usuarios. Para ello debe ejecutar las funciones fork() y execl(“/bin/bash”) que crea una nueva consola. Recuerde que debe guardar el pid asociado para poder comunicarse con ella. Finalmente, puede gestionar la lectura de comandos del usuario y su paso (p. ej.: Mediante la función write) a su correspondiente consola. No incluya la gestión de las respuestas de la consola al usuario. (20%) Otra información: #define N 20 #define SERVIDOR “192.168.5.254” #define SERVER_PORT 2199 #define N 20 #define LISTENQ N // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N a la vez. #define SERVER_PORT 2199 //Dato #define SERVIDOR “192.168.5.254” #define MSG_SIZE 256 //Tamaños maximos int main (int argc, char **argv) { int i, j, maxi, maxfd, listenfd, resto, connfd, sockfd, sockfd1, nready, numero, numero_resto; int client [N]; // Array de descriptores de los usuario int descriptores_locales[N]; //Se crea un array de “descriptores locales” para las consola (APARTADO C). char * login[N]; // Array de logins de usuarios, para ir guardándolos mientras llegan los passwwords. José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 82 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes char *password; // Password. No hace falta guardarlos porque sólo se utiliza una vez en “confirma”. ssize_t len; fd_set rset, allset; char * msg_rec; // Mensaje recibido char *aux; //Auxiliares para formar mensaje socklen_t clilen; struct sockaddr_in cliaddr, servaddr; //Arranque del servidor concurrente if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. maxfd=listenfd; maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; login[i]=NULL; consolas [i]=-1; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset){ //USUARIO NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario for (i=0; i<N; i++) //Actualización del array José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 83 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; // Los operarios van después de las líneas if (i>maxi) maxi=i; /* Si se quiere pasar el login del servidor en este instante se añadiría. No es solución óptima*/ // read (connfd, msg_rec, sizeof(numero)); //Se entiende que no se va a tx otra cosa // strcpy(login[i],numero); //Copia del login if (--nready<=0) continue; //Previsión para más de una interrupción } for (i=0; i<=maxi; i++){ if ((sockfd1 =client[i])<0) // Se van a comprobar todos los usuarios conectados continue; if (FD_ISSET(sockfd1, &rset)){ //Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec,MSG_SIZE))>0){ //El proceso de cierre no se pide… if (login[i]==NULL){ //Es el login. No password o comando. strcpy(login[i],msg_rec); } //Copia del login else if (consola[i]==0){ //NO es login, no es comando (la consola debería estar abierta) es password. strcpy(password, msg_rec); // Copia del password. if (confirma (login[i], password)!=0){// Cuando no es correcto… close (sockfd); client[i]=-1; login[i]=NULL; FD_CLR(sockfd1,&allset); if (maxi==i) --maxi;} if (--nready<=0) break; else continue; }else{ // Cuando es 0, es correcto y hay que proceder a crear las consolas… (Apartado C) int puerto_local=4000+i; // Buscamos un puerto “aleatorio”. if ((int sockfd = socket(AF_INET,SOCK_DGRAM,0))<= 0) { printf ("ERROR \n"); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 84 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes servaddr.sin_port=htons(puerto_local); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); } // El servidor ya tiene un puerto local con el que poder comunicarse con… pid=fork( ); // Se crea proceso hijo. Recordar guardar el pid. if (pid==0){ //El hijo va a ser la nueva consola… for (i = 0; i <= maxi; i++) if (client[i]>-1) { close(client[i]); close(descriptor_local[i]); } // Cerramos todos los puertos abiertos. close(listenfd); // Cerramos el puerto de atención a nuevas conexiones. Sólo queda abierto sockfd. // No hace falta inicializar variables, pues éstas no se volverán a utilizar. break; break; // Se sale de los bucles for en los que se encontraba el programa padre. // Y ya se puede proceder a crear la consola… execl(“/bin/sh”); // Se ejecuta la nueva consola. }else { //y el proceso padre… close(puerto_local); //Cierra el socket UDP… // Y para poder utilizar write en vez de sendto, más sencillo, se pasa a hacer un UDP conectado. if (descriptor_local[i]=socket(AF_INET, SOCK_DGRAM, 0))<= 0) { printf ("ERROR \n"; } if(connect(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); } } } //Fin del “else” principal }else{ // Atencion a comandos write(descriptor_local[i], msr_rec, len+1); } } } if (--nready<=0) continue; } //Previsión para más de una interrupción }Fin del for de clientes … José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 85 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes }// FIN del bucle principal for }// Fin del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 86 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Problema 2 (40% Ejercicios) Se diseña un servicio de telefonía móvil, en el que la estación base ofrece servicios muy diversos, entre los que se encuentran los mensajes de texto. Se pretende realizar el software de los terminales móviles, de manera que sean capaces en enviar y recibir los mensajes de texto referentes a este servicio. De esta forma, la aplicación consiste en atender simultáneamente al usuario del teléfono móvil por si desea mandar el mensaje y atender al servidor por si es éste el que manda el mensaje de otro usuario. Se pide: A) Realice el código necesario de conexión del terminal al servidor y mantener la concurrencia entre el usuario local (el teclado del terminal) y el servidor al que se ha conectado. (10%) B) Realice el código para mandar y recibir mensajes. En caso del envío, el teléfono incluye en el mensaje el propio número de teléfono de la forma: “Número_propio:mensaje”. De igual forma, en la recepción se recibe un mensaje del mismo tipo y se deben separar los dos campos, mostrando sólo el mensaje por la pantalla. (10%) C) Añada ahora una confirmación al usuario para proceder a la presentación por pantalla (por ejemplo, pulsar la tecla #) de un mensaje recibido desde el servidor, evitando bloquear la aplicación sólo por esta causa. Incluya un “timeout” de tiempo máximo de espera para esta confirmación (1 minuto) de forma que si no se realiza, se vuelve a la espera original. ( 20%) Otra información: #define MSG_SIZE 1024 //Tamaño máximo de los mensajes #define PUERTO_SERVIDOR 3000 #define SERVIDOR “192.168.3.254” #define numero_propio 100 El primer paso consiste en decidir si es un proceso cliente o servidor. Es un cliente porque se refiere a los terminales móviles con interfaces para usuario (STDIN) y para el servidor. El segundo paso es decidir el protocolo TCP ó UDP. UDP no permite asegurar que el mensaje llegue y además el servidor no podría saber el destino que corresponde a cada mensaje cuando tenga que enviarlos: luego es TCP. #define SERVER_PORT 3000 //Dato #define SERVIDOR “192.168.5.254” //Dato #define MSG_SIZE 1024 //Se sobreentiende que completo #define TECLADO 0 // Descriptor para el teclado #define PANTALLA 1 // Descriptor para la pantalla int main (int argc, char **argv) { int maxfd, listenfd, numero, sockfd1, nready; char* numero propio; ssize_t len; fd_set rset, allset; char * msg_env; //Mensaje enviado de conexión char * msg_rec1, *msg_rec2; // Mensaje recibido de conexión char *valor1, *valor2; //Auxiliares para formar mensaje socklen_t clilen; struct timeval * tv; //Variable temporal necesaria para el apartado C struct sockaddr_in servaddr; numero_propio= argv[1]; //Por ejemplo, se puede pasar así, no viene especificado en el enunciado. if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 87 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(connect(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))<0) { printf("ERROR \n"); exit (1); } if (listenfd>TECLADO) maxfd=listenfd; else maxfd =TECLADO; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; numeros[i]=-1; conexiones [i]=-1; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); //Socket hay que activarlo FD_SET(TECLADO, &allset); //Teclado hay que activarlo tv->tv_sec=NULL; tv->tv_usec=NULL; for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL, tv); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset){ //SERVIDOR if (len=read(listenfd, msg_rec1, MSG_SIZE)>0){ // Mensaje msg_env=strchr(msg_rec1, “:”); //Buscamos los “:” write(PANTALLA, msg_env++, strlen(msg_env)); tv->tv_sec=60; tv->tv_usec=0; } } if ( FD_ISSET(TECLADO, &rset){ //USUARIO José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 88 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if (len=read(TECLADO, msg_rec2, MSG_SIZE-strlen(numero_propio)-1)> 0){ // Mensaje if (strcmp(msg_rec1,”#”)==0){ msg_env=strchr(msg_rec1, “:”); //Buscamos los “:” write(PANTALLA, msg_env++, strlen(msg_env)); tv->tv_sec=NULL; tv->tv_usec=NULL; }else{ valor=numero_propio; msg_env=strcat(valor, “:”); //Ponemos los “:” msg_env=strcat(msg_env,msg_rec2); // Componemos el mensaje write(listenfd, msg_env, strlen(msg_env)); // Y tx al servidor tv->tv_sec=NULL; tv->tv_usec=NULL; } } } if (nready == 0){ //Expira el tiempo tv->tv_sec=NULL; tv->tv_usec=NULL; } //Inicializamos el sistema. } } José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 89 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 03 DE JULIO DE 2007 Problema 1 (50% Ejercicios) Se diseña un servicio TCP destinado a un videojuego distribuido. El servicio se encuentra distribuido entre todos los equipos de los jugadores que en ese momento juegan una partida del videojuego. El gráfico representa las conexiones de las aplicaciones una vez conectados los jugadores: Entre las tareas del servicio, se encuentran: − Gestionar las conexiones permanentes con el resto de jugadores. Éstos se conectan cuando desean realizar una partida. Habrá un total de N-1 conexiones de este tipo en cada servicio. − Gestionar la lectura de nicknames de los jugadores. Los usuarios sólo pueden enviar tres tipos de paquetes: su nickname, su fin de juego y los datos de situación referentes al juego en sí. − Gestionar la inclusión de nuevos jugadores con la partida ya comenzada. Se pide: A) Código para aceptar la conexión de nuevos jugadores y proporcionar la concurrencia entre ellos. Gestionar la lectura de los nickname’s de jugadores que se transmite en el primer mensaje de datos, que se recibe de un nuevo jugador. Procure proporcionar concurrencia en este proceso. (25%) B) Código para conectarse a un grupo o partida ya comenzada. En este caso el jugador busca a los jugadores ya conectados. Para ello, como conoce el número de puerto en el que funciona, va testeando las IP’s que el jugador local le va proporcionando por teclado. Cuando encuentra un jugador activo, le manda el nickname propio y recibe de este jugador a su vez su nickname . (25%) Otra información: #define N 20 #define SERVIDOR “192.168.5.254” #define SERVER_PORT 2399 #define NICKNAME nombrealumno //Cada alumno que ponga su nombre #define MSG_SIZE 256 // Tamaño maximo para los nicks, datos del juego y nicks+struct_sockaddr. #define N 20 #define LISTENQ N-1 // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N-1 a // la vez. #define NICKNAME alumnoLSC //Nick del jugador #define SERVER_PORT 2199 //Dato #define SERVIDOR “192.168.5.254” #define MSG_SIZE 256 //Tamaños maximos de mensajes int main (int argc, char **argv) { José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 90 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes int i, j, maxi, maxfd, listenfd, resto, connfd, sockfd, sockfd1, nready, numero, numero_resto; int client [N]; // Array de descriptores de los jugadores char * nickname [N]; // Array de nicks de usuarios, para ir guardándolos (en realidad N-1). char * IP [N]; //Array de caracteres para ir guardando las direcciones IP de los jugadores. ssize_t len; fd_set rset, allset; char * msg_rec; // Mensaje recibido char *IPCON; // Char para guardar la IP del jugador al que se conecta. socklen_t clilen; struct sockaddr_in servaddr; //Arranque de la parte de servidor concurrente, para aceptar nuevos jugadores. if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n";) exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. maxfd=listenfd; maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; nickname[i]=NULL; IP[i]=NULL; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); //Para el apartado B) donde hay que gestionar la conexión a nuevos juegos: FD_SET (0, &allset); for(;;){ rset=allset; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 91 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset){ //USUARIO NUEVO clilen=sizeof(cliaddr); if (connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen)<0) continue; //Se acepta el usuario for (i=0; i<N; i++){ //Actualización del array if (client[i]<0) { client[i]=connfd; break; } } IP[i]=cliaddr.sin_addr.s_addr; // Se guarda la dirección IP del nuevo jugador. FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; if (i>maxi) maxi=i; /* Si se quiere leer el nick del jugador en este instante se añadiría. No es solución concurrente*/ // read (connfd, msg_rec, sizeof(msg_rec)); //Se entiende que no se va a tx otra cosa // strcpy(nickname[i],msg_rec); //Copia del nick // Aquí se puede hacer comprobación de NICKNAME+IP y comprobar que no es un jugador repetido. if (--nready<=0) continue; //Previsión para más de una interrupción } for (i=0; i<=maxi; i++){ if ((sockfd1 =client[i])<0) // Se van a comprobar todos los usuarios conectados continue; if (FD_ISSET(sockfd1, &rset)){ //Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec,MSG_SIZE))>0) //El proceso de cierre no se pide… if (nickname[i]=NULL){ //Es el nick. strcpy(nickname [i],msg_rec); //Copia del nick. La IP ya estaba copiada en la conexión. //Según apartado B, cuando alguien se conecta se le manda el nick propio. if (strcmp(IP[i],IPCON)!=0) write(sockfd1, &NICKNAME, strlen(NICKNAME)); } }else{ //Es comando o dato del juego /* FALTA AÑADIR CÓDIGO DE FUNCIONAMIENTO DEL JUEGO. NI SE EXPLICA, NI SE PIDE.*/ } } if (--nready<=0) continue; } //Previsión para más de una interrupción } José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 92 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if (FD_ISSET(0, &rset)) // sale por el teclado. if (len=read (0, msg_rec, strlen(msg_rec))==strlen (SERVIDOR)) { // caso de que “parezca” una IP. // Aprovechamos servaddr que ya está configurado y: servaddr.sin_addr.s_addr= inet_addr (msg_rec); //Actualizamos IP. if ((sockfd= socket(AF_INET, SOCK_STREAM, 0))<0) continue;) if(connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))<0) close(sockfd); continue;} // Se intenta conectar al jugador indicado. //Y se gestiona la nueva conexión: for (i=0; i<N; i++) //Actualización del array if (client[i]<0) { client[i]=sockfd; break; } IP[i]=strdup(servaddr.sin_addr.s_addr); // Se guarda la dirección IP del nuevo jugador. IPCON=strdup(IP[i]); //Variable para saber a quién nos hemos conectado, para luego realizar el intercambio de nicks. FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (sockfd > maxfd) //Actualización de variables maxfd=sockfd; if (i>maxi) maxi=i; /* Se pasa el nick del jugador en este instante se añadiría. */ write (sockfd, &NICKNAME, strlen(NICKNAKE)); //Se entiende que no se va a tx otra cosa /* Si se quiere esperar el nick del otro jugador en este instante se añadiría, solución no conc. */ if ((len=read(sockfd, msg_rec,MSG_SIZE))>0){ if (nickname[i]=NULL) //Es el nick. strcpy(nickname[i],msg_rec); } //Copia del nick } //FIN del if (TECLADO) … }// FIN del bucle principal for }// Fin del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 93 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 15 DE SEPTIEMBRE DE 2006 Problema 1 (60% Ejercicios) Se diseña un servidor central TCP destinado al servicio de descubrimiento de servicios. El servicio consiste en que un usuario se conecta y el servicio le informa de dónde se encuentra el servicio que está buscando. El gráfico representa el sistema una vez conectados los usuarios: Entre las tareas del servidor, se encuentran: − Gestionar las conexiones permanentes con los usuarios. Éstos se conectan cuando desean descubrir (saber donde está) un servicio. Habrá un total de N conexiones de este tipo. − Gestionar la búsqueda del servicio en la única base de datos local. Esta base de datos se abre por el servidor en el arranque y no se vuelve a cerrar. Se considera la gestión de la base de datos idéntica a la de un fichero. − Gestionar la búsqueda de la localización del servicio (por su nombre) en la base de datos. La base de datos es simplemente una lista de “nombres” y “localizaciones”, con tamaños de 20 bytes y “sizeof (struct sockaddr)” respectivamente. La base de datos (y el servicio) devuelve la dirección y puerto del servicio buscado en formato “struct sockaddr”. Se pide: A) Código para aceptar la conexión de los usuarios y proporcionar la concurrencia. Recuerde que el proceso ha de ser completamente concurrente, es decir, que el servidor no puede quedarse atendiendo la búsqueda de un único usuario. Incluya también la apertura de la base de datos (que se realiza antes de la conexión de los clientes). (20%) B) Código de peticiones y resolución de la localización. Una vez se recibe el nombre del servicio (20 bytes), se debe buscar en la base de datos (se supone que siempre es accesible) y encontrar el nombre, lo que le sigue es su localización. Los registros son directamente nombre y localización (sin espacios) y se separan por un “INTRO” (dos bytes). (25%) C) Suponga ahora que la búsqueda no encuentra resultado en la base de datos. Gestione la conexión (TCP) y petición sobre otro servicio de descubrimiento externo. A su vez se espera la respuesta de este servicio y se responde al usuario. (15%) Otra información: #define N 100 #define SERVIDOR_EXTERNO “192.168.5.254” #define SERVER_PORT 2499 Nota importante: Suponga que el equipo donde se ejecuta el servidor DISCOVERY no tiene limitaciones de memoria, ni de número de puertos abiertos simultáneamente. El sistema operativo permite la concurrencia en la base de datos. #define N 100 #define LISTENQ N // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N a la vez. #define SERVER_PORT 2499 //Dato #define SERVIDOR _EXTERNO “192.168.5.254” //Del servicio externo #define MSG_SIZE 1024 //No se dice nada, mínimo mayor de 20 (tamaño del nombre del servicio buscado) #define BASE “BASE DE DATOS” //No se indica nombre. Nos hace falta para proceder a su apertura. José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 94 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes int main (int argc, char **argv) { int listenfd, connfd, sockfd, id, numfp; char *nombre; // Nombre que busca el cliente ssize_t len; char * datos; // para la base de datos char *nombre_comprobar; // Nombre extraido de la base de datos socklen_t clilen; struct sockaddr_in cliaddr, servaddr, servexternoaddr; //Hay 3, el propio, el cliente y el del servicio externo. fp=fopen(BASE, ‘r’); //Se abre la base de datos. “fp” en el proceso padre siempre apuntará al origen. numfp=fileno(fp); //Descriptor numérico, para facilitar la búsqueda. if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= htonl(INADDR_ANY); //Como no se conoce la direccion local, no se usa inet_addr servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. for (;;){ clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario if ((id=fork())<0) { printf (“Error\n”); continue; } else if (id>0){ //Proceso padre close (connfd); // Cerramos puerto del cliente y esperamos por más. }else{ //Proceso hijo close (listenfd); // se cierra puerto de conexiones. Los procesos ya están funcionados y conectados. /* ESPACIO PARA EL PROCESADO DEL HIJO APARTADOS B Y C */ if (read (connfd, nombre, 20)==0) { close(connfd); exit(0); }else{ //Se lee el nombre, y se comprueba si es 0. José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 95 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes while (!feof(fp)){ //Con el nombre vamos a buscar por toda la base de datos. read(datos, 20, numfp); // Leemos sólo la parte del nombre. Se podría leer todo y luego separar... nombre_comprobar=strdup(datos); //Duplicamos la cadena, nos hará falta, (se puede usar strcpy). fgets(datos, sizeof(struct sockaddr),fp); //Leemos lo que falta de la linea, ya que tenemos que // hacerlo tanto si es o no correcto. //Ahora toca comprobar: if (strcmp(nombre_comprobar,nombre)==0){ //Si lo es write (connfd, datos, strlen(datos)); //Rapidamente se envía la respuesta al cliente; //Se le puede hacer un casting a datos: (struct sockaddr *) &datos exit(0); } //El hijo no tiene nada más que hacer se termina. } //Fin del bucle while. if ((sockfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servexternoaddr, sizeof (servaddr)); servexternoaddr.sin_family= AF_INET; servexternoaddr.sin_addr.s_addr= inet_addr(SERVIDOR_EXTERNO); //Ahora sí se usa inet_addr servexternoaddr.sin_port=htons(SERVER_PORT); //El mismo que el propio, es otro como //DISCOVERY. if(connect(sockfd, (struct sockaddr *)&servexternoaddr, sizeof(servexternoaddr)<0){ //Y se conecta con el externo. printf("ERROR \n"); exit (1); } // Ahora hay que hacer lo que haria un cliente con el servidor:preguntar y esperar respuesta. Como el // proceso no tiene que realizar ninguna otra tarea se puede bloquear, aunque se deberia usar select para // limitar el tiempo de espera. write (sockfd, nombre_comparar, strlen(nombre_comparar)); //Mandamos el nombre. //Se espera respuesta. if (read ( sockfd, datos, sizeof (struct sockaddr))!=sizeof(struct sockaddr)){ write(connfd, “Dato no dispoble\n”); exit (1);) }else { write(connfd, datos,strlen (datos)); exit (0); } José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 96 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes } } // Fin del hijo. } Fin del for }Fin del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 97 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Problema 2 (50% Ejercicios) Se diseña un servicio de subscripciones a una lista de distribución de publicidad mediante mensajes cortos de texto. Este servicio consiste en enviarles SMS’s indiscriminadamente a números de usuario obtenidos de una base de datos y éstos, al abrir el mensaje, automáticamente responden al SMS quedando subscritos al servicio de publicidad. Se pretende realizar el software del servidor de mensajes, de manera que sea capaz en enviar y recibir los mensajes de texto referentes a este servicio y suscribir a los usuarios. De esta forma, la aplicación consiste en atender simultáneamente al envío de mensajes SMS (que los va leyendo de la base de datos “DATABASE”), enviar los mensajes a los teléfonos móviles y atender las respuestas de éstos y subscribirlos al servicio SPAM (enviando un mensaje SMS a otro servicio que se encarga de proporcionar la publicidad). Se pide: A) Realice el código necesario de arranque del servidor y mantener la concurrencia entre el envío indiscriminado de SMS’s y la atención de las posibles respuestas de los usuarios. (25%) B) Realice el código para mandar y recibir mensajes. En caso del envío, el servidor busca el destino en la base de datos “DATABASE” y obtiene el número del usuario junto con una estructura “struct sockaddr” que indica la dirección y puerto de funcionamiento de los terminales, bajo el formato “NÚMERO:SOCKADDR”. Con esta información el servidor genera un mensaje mediante la función char* genera(double número, struct sockaddr* clientaddr) que ya está programada (no suponga bloqueo al ejecutar esta función). En recepción, el servidor lee el mensaje, leyendo el origen, y enviando al servidor que funciona en el puerto 4500 de la misma máquina un mensaje con formato “SOCKADDR+conectado” donde SOCKADDR es la struct sockaddr que contiene dirección IP y puerto del usuario conectado. (25%). Otra información: #define MSG_SIZE 1024 //Tamaño máximo de los mensajes #define PUERTO_SERVIDOR 3000 #define SERVIDOR “192.168.3.254” El número de teléfono posee nueve cifras. Considere la base de datos como un archivo compuesto por la estructura “NÚMERO:SOCKADDR”, indefinidamente repetida. El primer paso es decidir el protocolo TCP ó UDP. TCP no permite mandar paquetes a distintos destinatarios por el mismo descriptor, además y sobre todo, se desconoce si se tiene cliente o servidor en el otro extremo. UDP resuelve estas dificultades. #define SERVER_PORT 3000 //Dato #define SERVIDOR “192.168.5.254” //Dato #define MSG_SIZE 1024 //Se sobreentiende que completo #define SPAM 4500 //Enunciado int main (int argc, char **argv) { int maxfd, listenfd, numfd, sockfd1, nready; char* numero propio; ssize_t len; fd_set rset, allset; char * msg_env; //Mensaje enviado char * msg_rec1, *msg_rec2; // Mensaje recibido de conexión char *valor1, *valor2; //Auxiliares para formar mensajes socklen_t clilen; FILE *fp; //descriptor para la base de datos. double numero; //Para el numero de la función “genera” struct timeval * tv; //Podría ser utilizada. struct sockaddr_in servaddr, cliaddr; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 98 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if ((listenfd = socket(AF_INET,SOCK_DGRAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); fp=fopen(“DATABASE”, “r”); // Se abre base de datos. int numfd=fileno(fp); FD_SET(listenfd, &allset); //Socket hay que activarlo FD_SET(numfd, &allset); //Database hay que activarlo if (numfp>listenfd) maxfd=numfp; else maxfd=listenfd; // Actualizacion maxfd for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL, NULL); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset){ //SERVIDOR //ATENCIÓN A LA LLEGADA DE RESPUESTA DE USUARIOS se recibe mensaje if (len=recvfrom(listenfd, msg_rec1, MSG_SIZE, 0, (struct sockaddr*)cliaddr, &len)>0){ // Mensaje msg_env=(char *)&cliaddr; // Se va formando el mensaje a tx al otro servicio. msg_env=strcat(msg_env,”+conectado”); // Se termina de formar el mensaje. servaddr.sin_port=htons(SPAM); // Destino del datagrama. sendto(listenfd, msg_env, strlen(msg_env), 0, (struct sockaddr*)&servaddr, sizeof (servaddr)); // Y se transmite el mensaje de información al otro servidor. } } if ( FD_ISSET(numfd, &rset){ //BASEDEDATOS - ATENCIÓN A LA INTERRUPCIÓN DE LA BASE DE DATOS, siempre mientras haya listado if (len=read(numfp, msg_rec2, MSG_SIZE)> 0){ // Se lee base de datos (Se puede medir el tamaño:9+1+sizeof(struct sockaddr)) numero=0; valor1=strdup(msg_rec2); valor2=valor1; //Extraccion número José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 99 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes for (i=0; i<9; i++) { valor1++; valor2++; } ++valor2=’\0’; for (i=0; i<9; i++) { numero=(atoi(valor1)*1ei)+numero; valor1--; --valor2=’\0’; } //Se extrae el número. Hay otras alternativas… (atof, atol). valor2=strchr (msg_rec2, ‘:’); cliaddr=(struct sockaddr_in) ++valor2; //Direccion msg_env=genera (numero, (struct sockaddr*) &cliaddr); //Generamos mensaje sendto(listenfd, msg_env, strlen(msg_env), 0, (struct sockaddr*)&cliaddr, sizeof (cliaddr)); } } } Fin del for } Fin del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 100 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 14 DE SEPTIEMBRE DE 2007 Problema 1 (50% Ejercicios) Se diseña un servicio TCP destinado a proporcionar concurrencia para el acceso a un servidor. El servicio consiste en que los usuarios se conectan, acceden (en caso de que sea posible), y se arranca la aplicación que los usuarios requieren del servidor. Entre las tareas del servicio, se encuentran: − Gestionar las conexiones permanentes de los usuarios. Éstos se conectan cuando desean acceder a algún servicio del servidor. Habrá un total de N conexiones de este tipo. − Gestionar la lectura de los comandos de usuarios. Los usuarios mediante la transmisión de comandos estándares de Linux pueden operar en la Maquina Servidor. Por tanto el servidor debe ser capaz de ejecutar estos comandos (incluyendo como tales los servicios de acceso). No se limita el número de comando a ejecutar en cada sesión. − Gestionar la devolución de parámetros según se produzcan o no en los servicios. Se pide: A) Código para aceptar la conexión de los usuarios y proporcionar la concurrencia. No existe control de acceso en esta máquina. (15%). B) Gestione la ejecución de los servicios de usuarios. Para ello debe ejecutar las funciones fork() y execl(“comando”) siendo “comando” lo que se recibe del usuario. La función “fork” genera un nuevo proceso (necesario para que el proceso sea concurrente) y execl ejecuta un comando. (20%) C) Incluya la recepción de parámetros de salida de los servicios y su transmisión al usuario que lo ha ejecutado. Para ello suponga que cada servicio antes de terminar el funcionamiento transmite un paquete UDP al puerto 4200+i (donde i es número del servicio: i є[1,N]) en el que se contiene esa información (no se requiere programar esta parte). Por ello, sea capaz de leer los datos de salida (en formato char*), y a continuación transmitirlos al usuario indicado. (15%). Otra información: #define N 20 #define SERVIDOR “192.168.3.254” #define SERVER_PORT 2399 #define MSG_SIZE 256 #define N 20 #define LISTENQ N // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N a la vez. #define SERVER_PORT 2399 //Dato #define SERVIDOR “192.168.3.254” José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 101 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes #define MSG_SIZE 256 //Tamaños maximos int main (int argc, char **argv) { int i, j, maxi, maxfd, listenfd, resto, connfd, sockfd, sockfd1, nready, numero, numero_resto; int client [N]; // Array de descriptores de los usuario int descriptores_locales[N]; //Se crea un array de “descriptores locales” para las respuestas de los // servicios. (APARTADO C). ssize_t len; fd_set rset, allset; char * msg_rec; // Mensaje recibido = comando socklen_t clilen; struct sockaddr_in servaddr; //Arranque del servidor concurrente if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. maxfd=listenfd; maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; login[i]=NULL; descriptors_locales [i]=-1; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 102 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if ( FD_ISSET(listenfd, &rset){ //USUARIO NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario for (i=0; i<N; i++) //Actualización del array if (client[i]<0) { client[i]=connfd; break; } FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; // Los operarios van después de las líneas if (i>maxi) maxi=i; if (--nready<=0) continue; //Previsión para más de una interrupción } // Como no hay control de acceso la atención a la conexión es genérica. for (i=0; i<=maxi; i++){ if ((sockfd1 =client[i])<0) // Se van a comprobar todos los usuarios conectados continue; if (FD_ISSET(sockfd1, &rset)) //Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec,MSG_SIZE))>0) { //El proceso de cierre no se pide… /* FALTA AÑADIR CÓDIGO DE ARRANQUE DE SERVICIOS*/ // Se ha enviado un comando -> arranque del servicio. // Por cada servicio aparecerá un proceso nuevo. //Aquí se debería incluir código para el apartado C: if (descriptores_locales[i]<0){ //Posición vacía descriptores_locales[i]=socket(AF_INET, SOCK_DGRAM, 0); serveraddr.sin_port=htons(4200+i); //Actualizamos puerto… if (bind (descriptores_locales[i], (struct sockaddr*)&serveraddr, sizeof(serveraddr))<0) printf (“Error/n”); FD_SET(descriptores_locales[i], &allset); //Se activa para cuando deba ser atendida. } //Hay que crear un proceso hijo para cada nuevo servicio. if (pid=fork()<0) printf(“Error /n”); else if (pid == 0){ //Proceso hijo… //Lo fundamental del hijo es cerrar todas las conexiones abiertas que no se deben solapar con el padre. close (listenfd); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 103 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes for (i = 0; i <= maxi; i++) if (client[i]>-1) { close(client[i]); } if(descriptores_locales[i] >0) close(descriptores_locales[i])}; //Y la última tarea del hijo es generar el servicio: if (execl(msg_rec)<0) printf(“Error /n”); //Esto dedicará este proceso a la ejecución del servicio. Cuando termine no hay nada más a hacer: exit(0); }else{ if (--nready<=0) continue; // No hay que hacer nada especial en el padre (servidor). } } if (--nready<=0) continue; } //Previsión para más de una interrupción }//Fin del for de clientes for (i=0; i<=maxi; i++){ if ((sockfd1 =descriptores_locales[i])<0) // Se van a comprobar todos los puertos continue; if (FD_ISSET(sockfd1, &rset)){ //Para el caso de que uno de ellos escriba algo if ((len=recvfrom(sockfd1, msg_rec,MSG_SIZE, 0, NULL, NULL))>0) { //Se sabe el origen… // Se responde write (client[i], msg_rec, strlen(msg_rec)); // Y se transmite al usuario } // Por último se libera el socket: FD_CLR(sockfd1, &allset); close (sockfd1); } } … }// FIN del bucle principal for }// Fin del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 104 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes Problema 2 (50% Ejercicios) Se diseña un servicio de transmisión de archivos (FTP) en una red LAN, por lo que se opta por implementar un servicio TFTP, basado en UDP. De esta forma, la aplicación consiste en atender simultáneamente la conexión de N usuarios que requieren descargar o cargar un archivo del servidor. La instrucción para cada caso es “get” y “put” respectivamente. Se pide: A) Realice el código necesario de arranque del servidor y mantener la atención de las peticiones de los usuarios. No hay control de acceso, al ser una LAN cerrada. (10%) B) Realice el código para que el servicio actúe correctamente como servicio TFTP. Sólo hay dos instrucciones válidas (get y put) seguidas de un espacio y el nombre de un archivo, es decir, “get filename” o “put filename”. En el caso de que se produzca una descarga deberá de abrirse el archivo, leerlo y mandarlo, y en caso de carga se tratará de abrir el archivo, leerlo y guardarlo. (25%). C) Añada un timeout al funcionamiento del servidor. Para agilizar el funcionamiento y que el sistema no se sature realice las modificaciones para que el tiempo máximo de carga o descarga de cada archivo de manera individualizada no supere los 5 minutos. (15%). Otra información: #define MSG_SIZE 1024 //Tamaño máximo de los mensajes tanto de comunicación como de los archivos #define PUERTO_SERVIDOR 3000 #define SERVIDOR “192.168.3.254” #define N 20 El enunciado indica claramente la naturaleza de la aplicación es un servidor UDP. La concurrencia para clientes UDP es natural, es decir, UDP es concurrente por sí mismo. Lo que ya no es concurrente automáticamente es cuando se tienen N clientes con N ficheros… hace falta select. Problema: gestionar concurrencia de diversos ficheros y relacionarlos con sus usuarios. Además pueden ser de salida (get) o entrada (put). #define SERVER_PORT 3000 //Dato #define SERVIDOR “192.168.3.254” //Dato #define MSG_SIZE 1024 //Se sobreentiende que completo #define N 20 //Dato int main (int argc, char **argv) { int maxfd, listenfd, numero, sockfd1, nready; char* numero propio; ssize_t len; fd_set rset, allset; char * msg; //Mensaje (simultáneamente sólo va a hacer falta uno). char *valor1, *valor2; //Auxiliares para separar mensaje socklen_t clilen; char buffer[MSG_SIZE]; struct timeval * tv; //Variable temporal necesaria para el apartado C struct sockaddr_in servaddr; struct sockaddr_in cliaddr; struct sockaddr_in clientddr [N]; // Array para guardar las direcciones de los clientes. int enviar[N]; // Array para separar get/put, por ejemplo get=0; put =1; inactivo=-1; int ficheros[N]; //Descriptores de ficheros en uso. José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 105 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes FILE *fp; if ((listenfd = socket(AF_INET,SOCK_DGRAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); // Todo servidor, incluye operación bind. if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))<0) { printf("ERROR \n"); exit (1); } for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; enviar[i]=-1; bzero(clientaddr[i], sizeof(struct sockaddr_in)); ficheros[i]=-1; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); //Socket hay que activarlo long iteracion= 300000; // 300/0,001 Este valor depende del tipo de PC, velocidad procesador… Un valor de 1 mseg, es una buena opción long iteraciones[N]; for (int k=0; k<N; k++) iteraciones[k]=-1; tv->tv_sec=0; tv->tv_usec=1000; for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL, tv); //Bloqueo en espera de entradas for (int k=0; k<N; k++){ if (enviar[k]>-1) // Está trabajando iteraciones[k]--; if (iteraciones[k]<=0) // Hay que cerrar… José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 106 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if (enviar[k]==0){ close(fichero[i] // Se cierra fichero; FD_CLR(fichero[i], &allset); } // Actualizar atención a fichero. bzero(clientaddr[i], sizeof(cliaddr)); enviar[k]=-1; iteraciones[k]=-1; }else{ close(fichero[i]); //Fin de archivo fichero[i]=-1; bzero(clientaddr[i], sizeof(cliaddr)); enviar[i]=-1; iteraciones[k]=-1; } } if ( FD_ISSET(listenfd, &rset){ //CLIENTES //ATENCIÓN A LA LLEGADA DE NUEVOS Clientes, pero hay que separarlos de una operación // put en curso (comando y operación “put” tendrán el mismo descriptor de entrada). if (len=recvfrom (listenfd, msg, MSG_SIZE, 0, (struct sockaddr *)&cliaddr, &clilen)<=0){ printf(“Error \n); }else{ for (i=0; i=N-1; i++) if (strcmp((char*)&clientaddr[i], (char *) &cliaddr))==0) { int encontrado =1; break; } if (encontrado ==0) { // Indica que el usuario no está conectado luego es nuevo; //Buscamos si lo que quiere es “get”o “put”) valor2=strchr(msg, “ “)++; //Nombre del fichero; char *filename=strdup(valor2); strncpy(valor1, msg, strlen(“put”)); // Se captura las tres primeras letras y… for (i=0; i=N-1;i++) if (enviar[i]==-1){ //No hay get ni put, luego está vacío.. if (strcmp(valor1, “get”)==0){ // Es una descarga clientaddr[i]= cliadd; enviar[i]=0; // Actualizamos variables. fp=fopen (filename, “r”); // Se abre fichero; fichero[i]=fileno(fp); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 107 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes FD_SET(fileno(fp), &allset); //Actualizar atención a fichero. }else{ // Es una carga… clientaddr[i]= cliadd; enviar[i]=1; // Actualizamos variables. fp=fopen (filename, “w+”); // Se abre fichero; fichero[i]=fileno(fp); } // NO hace falta atención a escritura. ... } }else{ // Está conectado-> está realizando una parte del “put”. //En i estará el índice del cliente. Simplemente queda escribir en fichero… write (fichero[i], msg, strlen (msg)); //Se supone paquetes máximos… y no maz. Si FIN if (len<MSG_SIZE) { for (j=0; j=len-1; j++) msg++; if (msg==’\0’) { close(fichero[i]); //Fin de archivo fichero[i]=-1; bzero(clientaddr[i], sizeof(cliaddr)); enviar[i]=-1; // Actualizamos variables if (--nready<=0) continue; } for (i=0; i<=N-1; i++){ if ((sockfd1 =ficheros[i])<0) // Se van a comprobar todos los archivos, para ver quién es continue; // el que tiene que transmitir. if (FD_ISSET(sockfd1, &rset)){ //Para el caso de que sea uno En modo get: for (j=0; j<MSG_SIZE; j++) { read (fichero[i], buffer[j], 1); // Se lee caracter a caracter… if (buffer[j]=’\0’) { //Fin de archivo en lectura.. enviar[i]=-1; // Actualizamos variables. close(fichero[i] // Se cierra fichero; FD_CLR(fichero[i], &allset); } // Actualizar atención a fichero. break; } sendto{listenfd, buffer, strlen(buffer), 0, (struct sockaddr*)& clientaddr[i], sizeof(cliaddr)); //Se tx paquete del fichero… if (buffer[j]=’\0’) //Fin de archivo en lectura bzero(clientaddr[i], sizeof(cliaddr)); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 108 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if (--nready<=0) continue; } } } //Fin del for } //Fin del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 109 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 05 DE FEBRERO DE 2008 Problema 2 (50% Ejercicios) Se diseña un servicio de voto por Internet mediante la activación de un código que llevan las papeletas individualizadas de los votantes. Un votante, que quiere votar con este sistema, solicita el envío de las papeletas “codificadas” de todas las candidaturas. Las papeletas le llegan a casa del votante con el código asignado y a partir de ese momento, y, en el plazo estipulado, puede realizar la votación. Para ello se conecta con el “servidor electoral”, se identifica con el certificado de usuario que posee y le da acceso al sistema electoral y por último introduce el código de la candidatura a la que pretende votar. Se pide: A) Realice el código necesario del “servidor electoral”, para que atienda la conexión de los electores. El servicio ha de ser capaz primero de aceptar la conexión y luego de leer el certificado que el usuario le envíe (le llega en el primer mensaje). Recuerde la concurrencia del proceso. (15%) B) Realice el código para comprobar la autenticidad del certificado. Para ello, el servidor se lo envía a otro servicio, una autoridad de certificación, que responde con “OK” ó “ERROR”. En el primer caso, el servicio pasará a autorizar la votación con un “OK” al votante, y en el segundo cerrará la conexión. Recuerde mantener la concurrencia del proceso. (25%) C) Por último, en caso de que todo el proceso sea válido, se procederá a permitir la lectura del código de votación. El código se almacenará en una base de datos (archivo) denominado “VOTACION”, incluyéndose simplemente el código seguido de un “\n”, para dejarlo listo para el siguiente votante. (10%) Otra información: #define N 20 #define MSG_SIZE 32 //Tamaño máximo de los códigos #define MSG_CERT 1024 // Tamaño máximo del certificado de usuario #define PUERTO 3000 #define SERVIDOR “192.168.3.254” # define AUTORIDAD “192.168.5.253” # define PTO_AUTORIDAD 2999 El primer paso consiste en decidir si es un proceso UDP ó TCP. Dado el tipo de información que se pretende enviar, la respuesta es obvia, es un servidor concurrente TCP. #define N 20 #define MSG_SIZE 32 //Tamaño máximo de los códigos #define MSG_CERT 1024 // Tamaño máximo del certificado de usuario #define PUERTO 3000 #define SERVIDOR “192.168.3.254” # define AUTORIDAD “192.168.5.253” # define PTO_AUTORIDAD 2999 #define LISTENQ N-1 int main ( ) { int maxfd, listenfd, numero, sockfd1, connfd, sockfd; char* numero propio; ssize_t len; fd_set rset, allset; char * msg_rec; // Mensaje recibido socklen_t clilen; José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 110 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes struct sockaddr_in servaddr; FILE *fp; // Para el archivo int i, j, maxi, maxfd, listenfd, connfd, sockfd, sockfd1, nready; int client [N]; // Array de descriptores de cada usuario int estado[N]; // Habrá que conocer en qué instante de la votación se encuentra, por ejemplo: 0 sin // certificado, 1 certificado leído y enviado y 2 listo para votar. Ahorra código… int desc_autoridad[N]; //Habrá un array de sockets para la autoridad… serán lógicamente TCP if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(PUERTO); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. maxfd=listenfd; maxi=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; estado [i]=-1; desc_autoridad[i]=-1; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); // Para el apartado C hay que abrir un archivo, se puede hacer ya… fp=fopen(“VOTACION”, “w+”); // Se abre el archivo for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas if ( FD_ISSET(listenfd, &rset)){ //USUARIO NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el usuario José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 111 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes for (i=0; i<N; i++) //Actualización del array if (client[i]<0) { client[i]=connfd; estado[i]=0; // Actualizamos arrays break; } FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; // Los operarios van después de las líneas if (i>maxi) maxi=i; if (--nready<=0) continue; //Previsión para más de una interrupción } for (i=0; i<=maxi; i++){ if ((sockfd1 =client[i])<0) // Se van a comprobar todos los clientes continue; if (FD_ISSET(sockfd1, &rset)) //Para el caso de que uno de ellos escriba algo if ((len=read(sockfd1, msg_rec, MSG_CERT))==0{ //Proceso de cierre en caso de //CLIENTE. NO SE PIDE. close(sockfd1); FD_CLR(sockfd1,&allset); client[i]=-1; estado[i]=-1; des_autoridad[i]=-1; if (maxi==i) --maxi; if (--nready<=0) break; else continue; else{ if (estado[i]==0){ //Se espera certificado // Hay que crear socket…. APARTADO B //Dos partes 1º mandar a la autoridad certificado // 2º Recibir resultado y actuar… // Primera parte… mandar el certificado… hay que crear un socket TCP… cliente. if ((sockfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (AUTORIDAD); José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 112 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes servaddr.sin_port=htons(PTO_AUTORIDAD); if (connect(sockfd,(struct sockaddr*) &seraddr, sizeof(servaddr)))<= 0) { printf ("ERROR \n"); exit(1); } //Una vez creado… se le manda el certificado por él… write (sockfd, msg_rec, strlen(msg_rec)); //Actualizamos descriptors, arrays… para estar atentos a su respuesta FD_SET(sockfd, &allset); desc_autoridad[i]=sockfd; estado[i]=1; //Estado de esperando respuesta.. } if (estado[i]==2) // Cuando se manda el código… APARTADO C. if (strlen(msg_rec)<=MSG_SIZE){ //Es un código: strcat (msg_rec,”\n”); //Se añade lo que se indica… fputs (msg_rec, strlen (msg_rec), fp); // Se escribe en “VOTACION” } // Y si se desea se puede cerrar al votante… para que no vote más… close(sockfd1); FD_CLR(sockfd1,&allset); client[i]=-1; estado[i]=-1; des_autoridad[i]=-1; if (maxi==i) --maxi; } if (--nready<=0) break; else continue; } if (--nready<=0) break; //Previsión para más de una interrupción }//Fin del for de clientes. for (i=0; i<=maxi; i++){ if ((sockfd1 =desc_autoridad[i])<0) // Se van a comprobar las conexiones con //“AUTORIDAD” continue; if (FD_ISSET(sockfd1, &rset)) { // Atención a los sockets de autoridad… //Cuando la autoridad responde, puede decir correcto o no… if ((len=read(sockfd1, msg_rec, MSG_SIZE))!=0) //No se plantea el fallo de la AUTORIDAD if (strcmp(msg_rec, “OK”)==0){ //Está bien… José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 113 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes estado[i]=2; //Se permite votar al votante write(client[i],”OK”, strlen(“OK”)); // Se le comunica a éste }else if (strcmp(msg_rec, “ERROR”)==0){ // Se le cierra al votante close(client[i]); FD_CLR(client[i],&allset); client[i]=-1; estado[i]=-1; des_autoridad[i]=-1; if (maxi==i) --maxi; } } FD_CLR(sockfd1, &allset); desc_autoridad[i]=-1; close (sockfd1); //Se cierra a la AUTORIDAD if (--nready<=0) break; else continue; } } //Fin del for } // Fin del for general }//Fin de main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 114 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes 03 DE FEBRERO DE 2009 Problema 1 (50% Ejercicios) Se diseña un servicio TCP concurrente en el que el los clientes se conectan para acceder a información que están generando aplicaciones que corren de manera autónoma en la misma máquina en el que se ejecuta el servicio. El gráfico representa las conexiones de las aplicaciones: Entre las tareas del servicio, se encuentran: − Gestionar las conexiones permanentes con los clientes. Éstos se conectan cuando desean acceder a una aplicación. Habrá un total de N conexiones de este tipo en el servidor. − Gestionar las conexiones permanentes con los servicios (actúan como clientes). Éstas se conectan cuando son arrancadas. Habrá un total de M conexiones de este tipo. − Gestionar la comunicación cliente-aplicación. Se pide: A) Código para aceptar la conexión de clientes. Éstos se conectan al servidor que les debe proporcionar servicio. El cliente indica el servicio (sólo uno por cliente) con un mensaje que indica su nombre mediante el código: ##nombreaplicación##. Recuerde utilizar un solo select para todo el ejercicio.(10%) B) Código para aceptar la conexión de los servicios. Éstos se conectan al servidor cuando se arrancan (en cualquier momento indeterminado). En el primer mensaje, indican su nombre mediante el conocido formato ##nombreaplicación##. Dada la igualdad de formatos no se admite la conexión a clientes de la misma máquina. Recuerde utilizar el mismo select para todo el ejercicio.(15%) C) Código para relacionar cliente y servicio. Al recibir el nombre del servicio, el servidor busca el nombre entre las aplicaciones ya conectadas. En caso de éxito, relaciona en un array cliente y servicio y responde al cliente con un “OK”. En caso de no encontrarlo se devuelve un “ERROR”.(25%) Otra información: #define N 20 #define M 29 #define SERVIDOR “192.168.5.254” #define SERVER_PORT 2399 #define MSG_SIZE 256 // Tamaño maximo para los mensajes #define N 20 //dato #define M 29 //dato #define LISTENQ N+M // Tamaño de lista de entrada de conexiones. En el peor de los casos son los N+M a la vez. #define SERVER_PORT 2399 //Dato #define SERVIDOR “192.168.5.254” #define MSG_SIZE 256 //Tamaños maximos José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 115 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes struct servicios { //aunque no se pide, parece interesante crear una estructura para guardar los datos… int sockfd; //puede llevar el descriptor de comunicación del . char * nombre; //puede llevar el nombre del servicio int descriptor_cliente; //también se le puede añadir el descriptor del cliente que lo está usando (apartado C) }; int main (int argc, char **argv) { int i, j, maxi, maxiser, maxfd, listenfd, sockfd1, nready; int client [N]; // Array de descriptores de los usuario int relaciones[N]; //Array de relaciones de clientes, para relacionar cliente->aplicación struct servicios local[M]; // Array de estructuras para los servicios ssize_t len; fd_set rset, allset; char msg_rec[MSG_SIZE]; // Mensaje recibido. socklen_t clilen; struct sockaddr_in cliaddr, servaddr; bzero(&cliaddr, sizeof(cliaddr)); // Será necesario luego. //Arranque del servidor concurrente if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) { printf ("ERROR \n"); exit(1); } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr.s_addr= inet_addr (SERVIDOR); servaddr.sin_port=htons(SERVER_PORT); if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0) { printf("ERROR \n"); exit (1); } listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes. maxfd=listenfd; maxi=-1; maxiser=-1; for (i=0; i<N;i++){ //Inicialización de los arrays de clientes client[i]=-1; relaciones[i]=-1; } for (i=0; i<M;i++){ //Hay dos tamaños distintos José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 116 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes local[i].sockfd=-1; local[i].descriptor_cliente=-1; local[i]->nombre=NULL; } FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores FD_ZERO(&rset); FD_SET(listenfd, &allset); for(;;){ rset=allset; nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas //Ahora la conexiones de clientes y servicios if ( FD_ISSET(listenfd, &rset){ //USUARIO NUEVO clilen=sizeof(cliaddr); connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta la conexión. //CÓDIGO APARTADO B //Aquí es cuando hay que diferenciar entre clientes y servicios if (strcmp((char *) &servaddr.sin_addr.s_addr, (char *) &cliaddr.sin_addr.s_addr))==0){ //Si es servicio. for (i=0; i<M; i++) //Actualización del array if (local[i].sockfd<0) { local[i].sockfd=connfd; break; } if (i>maxiser) maxiser=i; }else { //Si es cliente for (i=0; i<N; i++) //Actualización del array if (client[i]<0) { client[i]=connfd; break; } if (i>maxi) maxi=i; } FD_SET(connfd,&allset); //Actualización del conjunto de descriptores if (connfd > maxfd) //Actualización de variables maxfd=connfd; if (--nready<=0) continue; //Previsión para más de una interrupción } for (i=0; i<=maxi; i++){ José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 117 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if ((sockfd1 =client[i])<0) // Se van a comprobar todas los clientes continue; if (FD_ISSET(sockfd1, &rset)) //Se recibe algo if((len=read(sockfd1, msg_rec, MSG_SIZE))> 0){ //Se lee. No es vacío if (relaciones[N]<0){ //No está relacionado… luego es posible que se quiera conectar con algún servicio //Hay que comprobar que es un mensaje de nombre de servicio if ((len>4) && (msg_rec[0]==’#’) && (msg_rec[1]== ’#’) && (msg_rec[len-2]== ’#’) && (msg_rec[len-1]== ’#’)){ //Esta es la condicion de mensaje de nombre de servicio. //Ahora se pasa a comprobar si ese nombre está ya adquirido por el servidor (el servicio ya se ha //conectado). Como el mensaje es el mismo no hay ni que extraer el nombre del formato. j=0; while (strcmp (msg_rec, local[j]->nombre)!=0){ if (j>maxirec) break; j++; } if (j<=maxirec){ // Encontrado…. OK relaciones[i]=local[j].sockfd; //se actualizan relaciones local[j].descriptor_cliente=sockfd1; write (sockfd1, “OK”, strlen(“OK”)); // Se responde } else // No encontrado write (sockfd1, “ERROR”, strlen(“ERROR”)); //Se responde } } } } else { // RESTO ATENCIÓN CLIENTE NO SE PIDE } } //FIN ATENCIÓN CLIENTES if (--nready<=0) continue; // Por si no ha habido entrada de los servicios //SERVICIOS for (i=0; i<=maxirec; i++){ if ((sockfd1 =local.sockfd[i])<0) // Se van a comprobar todos los servicios continue; if (FD_ISSET(sockfd1, &rset)) //Se recibe algo if((len=read(sockfd1, msg_rec, MSG_SIZE))> 0) //Se lee. No es vacío //Habría que comprobar que es mensaje de identificación… José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 118 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes if ((len>4) && (msg_rec[0]==’#’) && (msg_rec[1]== ’#’) && (msg_rec[len-2]== ’#’) && (msg_rec[len-1]== ’#’)) //Aquí es muy sencillo… solo actualizar variable. local[i]->nombre=strdup(msrg_rec); // Se copia else { } else { } } //FIN ATENCIÓN SERVICIOS // AQUÍ SE INCLUIRÍA EL CÓDIGO DEL APARTADO C, Y RESTO. } //FIN del bucle principal for } //FIN del main José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 119 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838 CENTRO DE ESTUDIOS NOVA - Cartagena Laboratorio de Software de Comunicaciones – Ejercicios de Examenes José Antonio Márquez Paredes jamp@jamp.es Centro de Estudios Nova Avda. Pintor Pórtela, Esq. Carlos III, 3 30203 Cartagena Página 120 de 120 – Ejercicios deExamenes Telf.: 868973838-622373838