Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Ejercicio 1. Cliente.c #include <sys/types.h> #include <sys/socket.h> void main(int argc, char **argv) // en argv[1] == servidor { int sd; struct sockaddr_in server_addr; struct hostent *hp; if (argc != 2){ printf("Uso: client <direccion_servidor> \n"); exit(0); } sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); bzero((char *)&server_addr, sizeof(server_addr)); hp = gethostbyname (argv[1]); memcpy (&(server_addr.sin_addr), hp->h_addr, hp->h_length); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(4200); // se establece la conexión connect(sd, (struct sockaddr *) &server_addr, sizeof(server_addr)); // recibe la respuesta tm now; bzero(now, sizeof(tm)); recibir(sd, now, sizeof(tm)); printf("Date is %d/%02d/%02d\n", now->tm_year+1900, now->tm_mon+1, now->tm_mday); printf("Time is %02d:%02d\n", now->tm_hour, now->tm_min); close (sd); exit(0); } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Servidor.c #include <sys/types.h> #include <sys/socket.h> #include <time.h> void main(int argc, char *argv[]) { struct sockaddr_in server_addr, client_addr; int sd, sc; int size, val; int size; sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); val = 1; setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(int)); bzero((char *)&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(4200); bind(sd, &server_addr, sizeof(server_addr)); listen(sd, 5); size = sizeof(client_addr); while (1) { printf("esperando conexion\n"); sc = accept(sd, (struct sockaddr *)&client_addr,&size); time_t tim=time(NULL); tm *now=localtime(&tim); enviar(sc, now, sizeof(tm)); // envía el resultado close(sc); // cierra la conexión (sc) } close (sd); exit(0); } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Ejercicio 2 Cliente.c int mq_open(char *queue_name, int flags){ int sd; struct sockaddr_in server_addr; struct hostent *hp; sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); bzero((char *)&server_addr, sizeof(server_addr)); hp = gethostbyname (queue_name); memcpy (&(server_addr.sin_addr), hp->h_addr, hp->h_length); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(4200); // se establece la conexión connect(sd, (struct sockaddr *) &server_addr, sizeof(server_addr)); } int mq_close(int queue){ int op = OP_END; enviar(sd, &op, sizeof(int)); close(sd); } int mq_send(int sd, char *data, size_t len, int prio){ int op = OP_SEND; enviar(sd, &op, sizeof(int)); enviar(sd, &prio, sizeof(int)); enviar(sd, &len, sizeof(int)); enviar(sd, data, len); return 0; } int mq_receive(int sd, char *data, size_t *len, int *prio){ int op = OP_RECV; enviar(sd, &op, sizeof(int)); recibir (sd, &prio, sizeof(int)); recibir(sd, &len, sizeof(int)); recibir(sd, data, len); return 0; } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Servidor.c void main(int argc, char *argv[]) { struct sockaddr_in server_addr, client_addr; int sd, sc; int size, val; int size; int num[2], res; sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); val = 1; setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(int)); bzero((char *)&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(4200); bind(sd, &server_addr, sizeof(server_addr)); listen(sd, 5); size = sizeof(client_addr); while (1) { printf("esperando conexion\n"); sc = accept(sd, (struct sockaddr *)&client_addr,&size); tratar_peticion(sc); } close (sd); exit(0); } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. void tratar_peticion(void *value){ int sc = (int)value; do{ recibir(sd, &op, sizeof(int)); switch(op){ case OP_SEND: recibir(sd, &prio, sizeof(int)); recibir (sd, &len, sizeof(int)); recibir (sd, data, len); insertar (prio, data, len); break; case OP_RECV: obtener (&prio, data, len); enviar(sd, &prio, sizeof(int)); enviar (sd, &len, sizeof(int)); enviar (sd, data, len); break; } }while(op!=OP_END); close(sc); } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Ejercicio 3 a) TCP. Para evitar perdida de datos. b) El cliente (se encuentra en la maquina local) realiza las siguientes funciones: • Interfaz del usuario. • Enviar los mandatos introducidos por el usuario. • Recibir el resultado de las operaciones y los muestra por pantalla. El servidor (se encuentra en la maquina remota): • Recoge las peticiones del cliente. • Ejecuta el mandato • Devuelve el resultado al cliente c) Los mensajes que se enviarán serán: • Tamaño de los datos (4 bytes). • Datos o texto (sin tamaño determinado). El cliente genera el mensaje, a través de la interfaz de usuario y muestra el resultado de la petición. El servidor recibe y ejecuta el mandato. d) Cliente.c sd = conectar(); while (leer_cadena(shell) ¡= EOF){ len = strlen(shell); enviar(sd,&len, sizeof(int)); enviar(sd, shell, len); recibir(sd,&len, sizeof(int)); recibir(sd, shell, len); imprimir(shell, len); } close(sd); Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Servidor.c socket(…); bind(…); listen(…), while (1) { printf("esperando conexion\n"); sc = accept(sd, (struct sockaddr *)&client_addr,&size); tratar_peticion(sc); } close (sd); exit(0); } void tratar_peticion(sc) { char data [MAXDATA]; recibir(sd,&len, sizeof(int)); recibir(sd, shell, len); system(shell > foo); stat (foo, &st); enviar(sd,&st.st_size, sizeof(int)); size = 0; fd = open(foo) data_len = MAXDATA; while(st.st_size < size){ if (size+data_len > st.st_size ) data_len = st.st_size - size; s = leer(fd, data, data_len) enviar(sd, data, s); size += s; } close(fd); } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Ejercicio 4. a) TCP. Ya que es importante la fiabilidad y el orden de los mensajes. b) Existen 3 tipos de servicios: • CC • Puertas • Maquinas (de pago) Los pasos son los siguientes: • INICIO: o El CC (cliente) envía un mensaje de operación = LIBRE (1 byte) a las puertas (servidor). No hay respuesta. • FIN: o El CC (cliente) envía un mensaje de operación = CERRADO (1 byte) a las puertas (servidor). No hay respuesta. • Coche que quiere entrar en el parking: o El CC recibe el mensaje de la puerta. • Operación: 1byte -> ENTRAR • Fecha: 1 byte por día, mes, año (+año 2000), hora , minutos, y segundos (total 6 bytes) • 8 bytes matricula. Respuesta: • OK (1 byte) + estructura fecha + matricula (15 bytes). Se puede generar un mensaje nuevo desde el CC a las puertas: • OCUPADO. • Coche que quiere salir en el parking: o Genera un mensaje de LIBRE que se envía a todas las puertas. • Coche que quiere pagar en el parking: Mensajes desde taquilla al CC: • Enviado: o Operación: 1byte -> PAGAR o Fecha: 1 byte por día, mes, año (+año 2000), hora , minutos, y segundos (total 6 bytes) o 8 bytes matricula. • Respuesta (Coste): o Euros (4 bytes) o Céntimos (1 byte) Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. c) CC int main(){ crear_thread(&th1,control_puertas,“puerta1”); crear_thread(&th2,control_puertas,“puerta2”)); crear_thread(&th3,control_puertas,“puerta3”); crear_thread(&thN,control_maquinas,“maquina1”)); … Esperar(); } int control_ puertas (char *server){ control_puertas(char *server){ sd = conectar(server); insertar_array_conexiones(&sd); char tag = LIBRE; // = 1 enviar(sd,&tag, sizeof(char)); while(!cerrar){ recibir(sd, &datos, sizeof(datos)); tratar_datos(&datos, &res); numero_coches++; res.estado = LIBRE; enviar(sd,&res, sizeof(res)); if(numero_coches == MAXIMO) op = OCUPADO; activar_envio_todos(op); } } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. int control_ maquinas (char *server){ control_puertas(char *server){ sd = conectar(server); char tag = LIBRE; // = 1 enviar(sd,&tag, sizeof(char)); while (){ recibir(sd,&len, sizeof(int)); } close(sd); } Puertas socket(…); bind(…); listen(…), while (1) { printf("esperando conexion\n"); sc = accept(sd, (struct sockaddr *)&client_addr,&size); do{ recibir(sc, &estado, sizeof(char)); poner_estado(&estado); //LIBRE, COMPLETO, CERRADO switch(estado){ case LIBRE: break; case COMPLETO: break; case CERRADO: break; } }while(estado != CERRADO) close(sc); } close (sd); exit(0); Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. • Interrupciones: pulsador , introducir_ticket, abrir_barrera Mientras ejecuta el manejador el servidor puertas, se encuentra inhibido (el control lo tiene el manejador de la interrupción). void pulsador(){ if (estado == OCUPADO){ datos.op = ENTRAR; datos.fecha = now(); datos.matricula = get_matricula(); enviar(sc , datos, sizeof(datos)); //sc variable global recibir(sc , res, sizeof(res)); //sc variable global } } void abrir_barrrera(){ datos.op = SALIR; datos.fecha = now(); datos.matricula = get_matricula(); enviar(sc , datos, sizeof(datos)); //sc variable global recibir(sc , res, sizeof(res)); //sc variable global } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Maquinas expendedoras socket(…); bind(…); listen(…), while (1) { printf("esperando conexion\n"); sc = accept(sd, (struct sockaddr *)&client_addr,&size); do{ recibir(sc, &estado, sizeof(char)); poner_estado(&estado); //LIBRE, COMPLETO, CERRADO }while(estado != CERRADO) close(sc); } close (sd); exit(0); • Interrupciones: introducir_ticket Mientras ejecuta el manejador de la maquina de tickets, se encuentra inhibido (el control lo tiene el manejador de la interrupción). void introducir_ticket (){ enviar(sc , info, sizeof(info)); recibir(sc , coste, sizeof(coste); imprimir(coste); } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Ejercicio 5. Un edificio, con 200 despachos, desea construir una aplicación que le permita monitorizar la temperatura y humedad de cada uno de los despachos. Sensor 1 Monitor Sensor 200 Cada despacho consta de un sensor que toma cada segundo la temperatura y humedad del despacho. Se dispone de un computador que hace de monitor y que permite visualizar los datos de todos los despachos. El funcionamiento de la aplicación es el siguiente: cuando un despacho se abre por las mañanas, el sensor situado en ese despacho envía un mensaje al monitor indicándole que va a comenzar el proceso de monitorización. Cada segundo envía al monitor los datos de temperatura y humedad del despacho. Cuando el despacho se cierra por las tardes, el sensor envía un mensaje al monitor indicándole que deja de enviarle datos. Suponiendo que se desea construir una aplicación cliente-servidor utilizando sockets, se pide: a) Identifique en qué computador reside el cliente y en cuál el servidor. b) ¿Qué tipo de sockets emplearía para esta aplicación? ¿Por qué? c) Especifique el formato de los mensajes a intercambiar entre el cliente y el servidor y la secuencia de mensajes a intercambiar entre ellos. Haga una estimación del tamaño que ocuparían los mensajes. De acuerdo al tipo de sockets empleado en el apartado b, indique qué llamadas de la biblioteca de sockets utilizaría en el cliente y en el servidor. Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. a) El servidor se encuentra en el monitor. Los clientes se encuentran en los sensores. b) UDP. Ya que la pérdida de un dato no es relevante (lo es mas el rendimiento). c) struct datos{ char activar; // comunicación 1- activa, 0-desactivada char despacho; int temp; int humedad; } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Sensor void main(int argc, char *argv[]) { struct sockaddr_in server_addr, client_addr; struct hostent *hp; if (argc != 2){ printf("Uso: cliente <direccion_servidor> \n"); exit(0); } s = socket(AF_INET, SOCK_DGRAM, 0); hp = gethostbyname (argv[1]); bzero((char *)&server_addr, sizeof(server_addr)); memcpy (&(server_addr.sin_addr), hp->h_addr, hp->h_length); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(7200); bzero((char *)&client_addr, sizeof(client_addr)); client_addr.sin_family = AF_INET; client_addr.sin_addr.s_addr = INADDR_ANY; client_addr.sin_port = htons(0); bind (s, (struct sockaddr *)&client_addr, sizeof(client_addr)); while(enviar){ t1 = time() get_datos(&datos) datos.activa = 1; sendto(s, (char *)datos, sizeof(datos), 0, (struct sockaddr *) &server_addr, sizeof(server_addr)); t2 = time() sleep(1-(t2-t1)); } datos.activa = 0; sendto(s, (char *)&datos, sizeof(datos), 0, (struct sockaddr *) &server_addr, sizeof(server_addr)); close(s); } Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Monitor #include <sys/types.h> #include <sys/socket.h> void main(void) { int s, res, clilen; struct sockaddr_in server_addr, client_addr; s = socket(AF_INET, SOCK_DGRAM, 0); bzero((char *)&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(7200); bind(s, (struct sockaddr *)&server_addr, sizeof(server_addr)); clilen = sizeof(client_addr); while (1) { recvfrom(s, (char *) &datos, izeof(datos), 0, (struct sockaddr *)&client_addr, &clilen); Imprimir(&datos); } } /* fin main */ Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Ejercicio 6. a) Los mensajes los genera la estación central. El que las procesa son las máquinas. b) Si no fuera orientado a conexión, sería necesario usar un sistema de confirmación de envío y recepción de los datos a través de UDP. Por ejemplo: si se realiza la operación setdaytime() por parte de la estación central a una maquina, es necesario realizar después la operación getdaytime() para comprobar que la operación se ha realizado. En caso de la recepción de los datos, para evitar bloqueos usar temporizadores (con la llamada select por ejemplo) c) struct time_st { char date[25]; } Servicio daytime socket(…); bind(…);//Puerto 13 listen(…), while (1) { printf("esperando conexion\n"); sc = accept(sd, (struct sockaddr *)&client_addr,&size); obtenertiempo(&datatime); enviar(sc, &datatime, sizeof(datatime)); close(sc); } close (sd); exit(0); Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Servicio setdaytime socket(…); bind(…);//Puerto 14 listen(…), while (1) { printf("esperando conexion\n"); sc = accept(sd, (struct sockaddr *)&client_addr,&size); recibir(sc, &datatime, sizeof(datatime)); cambiartiempo(&datatime); close(sc); } close (sd); exit(0); Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. Estación central sincronizado = 0; while (!sincronizado){ fd = open(configuracion) i = 0; while(!feof(fd)){ server=leer(fd) sd = conectar(server, 13); read(sd, datetime[i], sizeof(datetime[i])); close(sd); i ++; } sincronizado = comprobar(datetime, 5s); If (!sincronizado){ calcular_time(&datetime_new); fd = open(configuracion) while(!feof(fd)){ server=leer(fd) sd = conectar(server, 14); write(sd, datetime_new, sizeof(datetime_new)); close(sd); i ++; } } } } d) En principio no ya que la estación central realiza las operaciones de cliente y el resto de servidor. d) Se necesitaría un servicio que devolviese el nombre de la maquina. Esto es posible usando comunicaciones a través de broadcast (usando un puerto prefijado). En este caso, un servidor escucharía en un puerto determinado en cada una de las máquinas, y la estación central enviaría un mensaje de broadcast a ese puerto. Departamento de Informática Grado en Ingeniería Informática Sistemas Distribuidos Ejercicios de sockets NIA: ………………………………………………… GRUPO: ………………………………………………………… Nombre y apellidos: ………………………………………………………………………………………………….. if ((he=gethostbyname(“10.0.0.255”) == NULL) { //para usar broadcast perror("gethostbyname"); exit(1); } if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket"); exit(1); } struct sockaddr_in their_addr; // connector's address information their_addr.sin_family = AF_INET; // host byte order their_addr.sin_port = htons(SERVERPORT); // short, network byte order their_addr.sin_addr = *((struct in_addr *)he->h_addr); memset(their_addr.sin_zero, '\0', sizeof their_addr.sin_zero); int broadcast = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast) == -1) { perror("setsockopt (SO_BROADCAST)"); exit(1); } sendto(s, (char *)&data, sizeof(data), 0, (struct sockaddr *) &server_addr, sizeof(server_addr));