CENTRO DE ESTUDIOS NOVA

Anuncio
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones – Ejercicios de Examenes
José Antonio Márquez Paredes
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
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
[email protected]
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Página 120 de 120 – Ejercicios deExamenes
Telf.: 868973838-622373838
Descargar