Tema 5 Comunicación con sockets Grupo ARCOS Sistemas Distribuidos Grado en Ingeniería Informática Universidad Carlos III de Madrid Contenido Conceptos básicos sobre sockets Modelo de comunicación Sockets Datagrama Stream API de programación Sockets en C Sockets en Java Guía de diseño de aplicaciones cliente-servidor 2 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets: introducción Mecanismo de IPC que proporciona comunicación entre procesos que ejecutan en máquinas distintas Aparecieron en 1981 en UNIX BSD 4.2 Intento de incluir TCP/IP en UNIX Diseño independiente del protocolo de comunicación Un socket es un descriptor de un punto final de comunicación (dirección IP y puerto) Abstracción que: Representa un extremo de una comunicación bidireccional con una dirección asociada Ofrece interfaz de acceso a los servicios de red en el nivel de transporte Protocolo TCP y UDP 3 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets: introducción Aplicaciones/servicios RMI and RPC Sockets Aplanamiento (marshalling), representación externa de datos Protocolo de transporte UDP y TCP 4 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets: introducción Sujetos a proceso de estandarización dentro de POSIX (POSIX 1003.1g) Actualmente disponibles en: Casi todos los sistemas UNIX Prácticamente todos los sistemas operativos WinSock: API de sockets de Windows Macintosh En Java como clase nativa 5 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets UNIX Dominios de comunicación AF_UNIX AF_INET Tipos de sockets Stream (SOCK_STREAM) Datragrama (SOCK_DGRAM) Direcciones de sockets 6 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Dominios de comunicación Un dominio representa una familia de protocolos Un socket está asociado a un dominio desde su creación Sólo se pueden comunicar sockets del mismo dominio Los servicios de sockets son independientes del dominio Ejemplos de dominios: AF_UNIX (o AF_LOCAL): comunicación dentro de una máquina AF_INET: comunicación usando protocolos TCP/IP 7 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Tipos de sockets Stream (SOCK_STREAM) Protocolo TCP Datagrama (SOCK_DGRAM) Protocolo UDP Raw (SOCK_RAW) Sockets sin protocolo de transporte 8 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets stream Protocolo TCP (RFC 793) Flujo de datos bidireccional Orientado a conexión Debe establecerse una conexión extremo-a-extremo antes del envío y recepción de datos Proporcionan fiabilidad Paquetes ordenados por secuencia, sin duplicación de paquetes, libre de errores Ejemplos: HTTP, Telnet, FTP, SMTP 9 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets datagrama Protocolo UDP (RFC 768) Flujo de datos bidireccional No orientado a conexión No se establece/mantiene una conexión entre los procesos que comunican Un datagrama es una entidad autocontenida Longitud máxima de un datagrama (datos y cabeceras) es 64 KB Mantiene separación entre paquetes No proporcionan fiabilidad Paquetes desordenados, duplicados, pérdidas Ejemplos: DNS 10 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets: stream y datagramas socket API runtime support Process A Process B socket API runtime support transport layer software transport layer software connectionless datagram socket a datagram a logical connection created and maintained by the runtime support of the datagram socket API socket API runtime support Process A Process B socket API runtime support transport layer software transport layer software connection-oriented datagram socket 11 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Correspondencia entre familia y tipos de sockets TIPO SOCKET AF_UNIX AF_INET SOCK_STREAM Yes TCP SOCK_DGRAM Yes UDP SOCK_RAW IP SOCK_SEQPACKT FAMILIA TIPO Protocolo Protocolo actual AF_INET SOCK_DGRAM IPPROTO_UDP UDP AF_INET SOCK_STREAM IPPROTO_TCP TCP AF_INET SOCK_RAW IPPROTO_ICMP ICMP AF_INET SOCK_RAW IPPROTO_RAW raw 12 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Direcciones de sockets Cada socket debe tener asignada una dirección única Dirección de host (32 bits) + puerto (16 bits) + protocolo Las direcciones se usan para: Asignar una dirección local a un socket (bind) Especificar una dirección remota (connect o sendto) Las direcciones son dependientes del dominio Se utiliza la estructura genérica struct sockaddr Cada dominio usa una estructura específica Direcciones en AF_UNIX (struct sockaddr_un) Nombre de fichero Direcciones en AF_INET(struct sockaddr_in) Es necesario la conversión de tipos (casting) en las llamadas 13 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Puertos Un puerto identifica un destino en un computador Los puertos se asocian a procesos, de manera que permiten que la transmisión se dirija a un proceso específico en el computador destino Un puerto tiene un único receptor y múltiples emisores (excepto multicast) Toda aplicación que desee enviar y recibir datos debe abrir un puerto Número entero de 16 bits 2^16 puertos en una máquina ~ 65536 puertos posibles Reservados por la IANA para aplicaciones de Internet: 0-1023 (también llamados well-known puertos) Puertos entre 1024 y 49151 son puertos registrados para ser usados por los servicios Puertos por encima de 65535 para uso privado El espacio de puertos para streams y datagramas es independiente http://www.iana.org/assignments/port-numbers 14 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Información asociada a una comunicación Protocolo TCP, UDP Dirección IP local (origen) Puerto local (origen) Dirección IP remota (destino) Puerto remoto (destino) (Protocolo, IP-local, P-local, IP-remoto, P-remoto) 15 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Encapsulación de un paquete TCP Datos 16 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Encapsulación de un paquete TCP Datos Puerto Origen Puerto Destino Cabecera TCP 17 Datos ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Encapsulación de un paquete TCP Datos Puerto Origen Puerto Destino Cabecera TCP Protocolo =TCP IP Origen IP Destino 18 Cabecera IP Cabecera TCP Datos Datos ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Encapsulación de un paquete TCP Datos Puerto Origen Puerto Destino Cabecera TCP Protocolo =TCP IP Origen IP Destino Tipo de trama = IP Dirección Eth. Origen Dirección Eth. Destino 19 Cabecera Ethernet Cabecera IP Cabecera TCP Cabecera IP Cabecera TCP Datos Datos Datos Cola Ethernet ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Direcciones IP Una dirección IP se almacena en una estructura de tipo in_addr #include <netinet/in.h> typedef uint32_t in_addr_t; struct in_addr { in_addr_t s_addr; }; 20 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Direcciones de sockets en AF_INET Estructura struct sockaddr_in Debe iniciarse a 0 La estructura tiene tres campos importantes: sin_family: sin_port: sin_addr: dominio (AF_INET) puerto dirección del host #include <netinet/in.h> struct sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; 21 struct sockaddr_in family 2-byte port 4-byte Net ID, host ID unused ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Direcciones de sockets en AF_UNIX La estructura struct sockaddr_un describe la dirección de un socket AF_LOCAL o AF_UNIX struct sockaddr_un family #include <sys/un.h> struct sockaddr_un { short sun_family; char sun_path[108]; }; 22 Pathname (up to 108 bytes) ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Servicios sobre direcciones Obtener el nombre de un host Transformar direcciones Obtener la dirección de un host Representación de datos Interna Externa 23 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Obtener el nombre de un host Función que facilita el nombre de la máquina en la que se ejecuta: int gethostname(char *name, size_t namelen); donde: name namelen 24 referencia al buffer donde se almacena el nombre longitud del buffer ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo I: obtener nombre host #include <unistd.h> void main () { char maquina[256]; int err; err = gethostname(maquina, 256); printf(“Ejecuto en la maquina %s\n”, maquina); exit(0); } 25 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Transformación de direcciones The McGraw-Hill 26 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Obtención de la dirección de host Usuarios manejan direcciones en forma de texto: Notación decimal-punto (ej: 138.100.8.100) Notación dominio-punto (ej. www.uc3m.es) Dos funciones de transformación de direcciones: Devuelve una dirección IP en notación decimal-punto char *inet_ntoa(struct in_addr in); Obtiene una dirección IP a partir de notación decimal punto int inet_aton(const char *cp, struct in_addr *in); 27 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo II: transformación de direcciones #include <netdb.h> #include <stdio.h> void main(int argc, char **argv){ struct in_addr in; if (argc != 2) { printf("Uso: %s <decimal-punto>\n", argv[0]); exit(0); } if (inet_aton(argv[1], &in) == 0) { printf("Error en la dirección\n"); exit(0); } printf("La dirección es %s\n", inet_ntoa(in)); exit(0); } 28 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Obtener la dirección de host Obtiene la información de un host a partir de una dirección en formato dominio-punto struct hostent *gethostbyname(char *str); Argumentos: str es el nombre de la máquina Obtiene la información de un host a partir de una dirección IP struct hostent *gethostbyaddr(void *addr, int len, int type); Argumentos: addr es un puntero a una estructura de tipo struct in_addr len es el tamaño de la estructura type es AF_INET 29 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Estructura hostent The McGraw-Hill 30 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo III: obtener la dirección de host en dominio-punto #include <netdb.h> #include <stdio.h> #include <string.h> void main(int argc, char **argv) { struct hostent *hp; struct in_addr in; hp = gethostbyname(“www.uc3m.es”); if (hp == NULL) { printf(“Error en gethostbyname\n”); exit(0); } memcpy(&in.s_addr,*(hp->h_addr_list),sizeof(in.s_addr)); printf(“%s es %s\n”, hp->h_name, inet_ntoa(in)); } 31 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo IV: obtener la dirección de host en decimal-punto #include <netdb.h> #include <stdio.h> #include <string.h> main(int argc, const { u_int addr; char **p; char **q; char **argv) struct hostent *hp; struct in_addr in; if (argc != 2) { printf("USO: %s Direccion-IP\n", argv[0]); exit (1); } err = inet_aton(argv[1], &addr); if (err == 0) { printf("Direccion IP en formato a.b.c.d\n"); exit (2); } 32 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo IV: obtener la dirección de host en decimal-punto hp=gethostbyaddr((char *) &addr, sizeof (addr), AF_INET); if (hp == NULL) { printf(“Error en ....\”n); exit (3); } for (p = hp->h_addr_list; *p!=0;p++){ memcpy(&in.s_addr, *p, sizeof(in.s_addr)); printf("%s\t%s",inet_ntoa(in), hp->h_name); for (q=hp->h_aliases;*q != 0; q++) printf("%s\n", *q); } exit(0); } 33 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Orden de los bytes Big-endian es el estándar para el ordenamiento de los bytes usado en TCP/IP También llamado Network byte order Big-endian Little-endian 34 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo: Representación del 1 Big Endian LSB MSB 0 Direcciones: 0 n 0 n+1 n+2 n+3 Dirección de crecimiento Little Endian LSB 1 Direcciones: 1 n MSB 0 0 n+1 n+2 0 n+3 Dirección de crecimiento 35 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Representación de datos Empaquetamiento de datos (marshalling): Serialización de las estructuras de datos y conversión de los valores de los datos a su representación externa “Esto es una cadena” Representación en el computador A 1.2 7.3 -1.5 …10010111…0110010… Desempaquetamiento de datos (unmarshalling) Conversión de los datos a su representación interna “Esto es una cadena” 36 Representación en el computador B 1.2 7.3 -1.5 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Funciones de transformación: network host En computadores que no utilicen big-endian (ej. procesadores Intel) es necesario emplear funciones para traducir números entre el formato que utiliza TCP/IP (big-endian) y el empleado por el propio computador (little-endian) : Host (Little-Endian) Network (Big-Endian) Traduce un número de 32/16 bits representado en el formato del computador al formato de red (TCP/IP) u_long htonl(u_long hostlong) u_short htons(u_short hostshort) Network (Big-Endian) host (Little-Endian) Traduce un número de 32/16 bits representado en el formato de red (TCP/IP) al formato del computador u_long ntohl(u_long netlong) u_short ntohs(u_short netshort) 37 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Funciones de transformación The McGraw-Hill 38 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Modelos de comunicación Sockets stream (SOCK_STREAM) Orientado a conexión TCP Sockets datagrama (SOCK_DGRAM) No orientado a conexión UDP 39 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Modelo de comunicación con sockets stream Proceso servidor socket() Proceso cliente bind() listen() socket() Conexión connect() write() Petición Respuesta 40 accept() read() read() write() close() close() ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Modelo de comunicación con sockets datagrama Proceso servidor socket() Proceso cliente bind() socket() Petición sendto() recvfrom() Respuesta recvfrom() close() 41 sendto() close() ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Primitivas POSIX para la gestión de sockets Creación de un socket (socket) Asignación de direcciones (bind) Preparar para aceptar conexiones (listen) Aceptar una conexión (accept) Solicitud de conexión (connect) Obtener la dirección de un socket Transferencia de datos Streams Datagramas Cerrar un socket (close) 42 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Creación de un socket (socket) Crear un socket: #include <sys/types.h> #include <sys/socket.h> int socket(int dominio, int tipo, int protocolo) Argumentos: dominio tipo protocolo AF_UNIX,AF_INET SOCK_STREAM,SOCK_DGRAM dependiente del dominio y tipo 0 elige el más adecuado Especificados en /etc/protocols devuelve: si éxito, un descriptor de socket si error, -1 El socket creado no tiene dirección asignada 43 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo V: Crear un socket #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #define TCP 6 #define UDP 17 /* ver /etc/protocols */ int main() { /* VARIABLES DEL PROGRAMA */ int sockfd; if ((sockfd=socket(AF_INET, SOCK_STREAM, TCP))==-1) { printf(“Error en la creación del socket”); exit(-1); } /* CONTINUACIÓN DEL PROGRAMA */ } 44 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Asignación de direcciones (bind) Asignar dirección a un socket: #include <sys/types.h> #include <sys/socket.h> int bind(int sd, struct sockaddr *dir, int long) Argumentos: sd dir long descriptor devuelto por socket dirección a asignar longitud de la dirección/tamaño de la estructura sockaddr devuelve –1 si error y 0 si se ejecutó con éxito Direcciones en dominio AF_INET (struct sockaddr_in) Host: una dirección local IP INNADDR_ANY: elige cualquiera de la máquina Puertos: 65535 puertos disponibles, de los cuales 0..1023 están reservados Si 0, el sistema elige uno Si no se asigna dirección al socket (típico en clientes) Se le asigna automáticamente (puerto efímero) en la su primera utilización (connect o sendto) 45 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Obtener la dirección de un socket Obtener la dirección a partir del descriptor: int getsockname(int sd, struct sockaddr *dir, int *long) sd dir long: descriptor devuelto por socket dirección del socket devuelta parámetro valor-resultado (igual que en accept) Obtener la dirección del socket en el otro extremo de la conexión: int getpeername(int sd, struct sockaddr *dir, int *long) sd dir long 46 descriptor devuelto por socket dirección del socket remoto parámetro valor-resultado ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Preparar para aceptar conexiones (listen) Habilita un socket para recibir conexiones en el servidor TCP Realizada en el servidor stream después de socket y bind #include <sys/types.h> #include <sys/socket.h> int listen(int sd, int baklog) Argumentos: sd: backlog: descriptor devuelto por socket número máximo de peticiones que se encolarán (algunos manuales recomiendan 5) antes de ejecutar accept devuelve –1 si error y 0 si se ejecutó con éxito 47 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Aceptar una conexión (accept) Realizada en el servidor stream después de socket, bind y listen Bloquea al servidor hasta que se produce la conexión; el servidor obtiene: La dirección del socket del cliente Un nuevo descriptor que queda conectado al socket del cliente Después de la conexión quedan activos dos sockets en el servidor: El original para aceptar nuevas conexiones El nuevo para enviar/recibir datos por la conexión establecida 48 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Aceptar una conexión (accept) #include <sys/types.h> #include <sys/socket.h> int accept(int sd, struct sockaddr *dir, int *long) Argumentos: sd dir long descriptor devuelto por socket dirección del socket del cliente parámetro valor-resultado: 1) Antes de la llamada: tamaño de dir 2) Después de la llamada: tamaño de la dirección del cliente que se devuelve Devuelve un nuevo descriptor de socket asociado a la conexión -1 en caso de error 49 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Solicitud de conexión (connect) Realizada en el cliente stream para conectarse al servidor #include <sys/types.h> #include <sys/socket.h> int connect(int sd, struct sockaddr *dir, int long) Argumentos: sd dir long descriptor devuelto por socket dirección del socket remoto longitud de la dirección devuelve –1 si error y 0 si se ejecutó con éxito Si el socket no tiene dirección asignada, se le asigna una automáticamente 50 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Establecimiento de una conexión en TCP 51 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Proceso servidor Ejemplo VI: Establecimiento de conexión TCP (clientes) socket() Proceso cliente bind() listen() socket() Conexión connect() int main() { int sockfd; struct sockaddr_in server; write() Petición Respuesta accept() read() read() write() close() close() if ((sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1){ printf(“Error en la creación del socket”); exit(-1); } server.sin_family = AF_INET; server.sin_port = htons(PORT_SERVER); server.sin_addr.s_addr = htonl(IP_SERVER); if (connect(sockfd,(struct sockaddr *)&server, sizeof(server)) <0) { printf(“Error en el connect”); exit(-1); } /* CONTINUACION CODIGO CLIENTE */ } 52 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Proceso servidor Ejemplo VI: Establecimiento de conexión TCP (servidores) int main() socket() Proceso cliente bind() listen() socket() Conexión connect() write() Petición Respuesta { accept() read() read() write() close() close() int sd, newsd, size; struct sockaddr_in server, client; if ((sd=socket(AF_INET, SOCK_STREAM, 0))==-1){ printf(“Error en la creación del socket”); exit(-1); } server.sin_family = AF_INET; server.sin_port = htons(PORT_SERVER); server.sin_addr.s_addr = htonl(IP_SERVER); /* bind */ if (bind(sd,(struct sockaddr *)&server, sizeof(server)) <0) { printf(“Error en el bind”); exit(-1); } 53 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Proceso servidor Ejemplo VI: continuación (servidores) listen(sd,5) for (;;) { socket() Proceso cliente bind() listen() socket() Conexión connect() write() Petición Respuesta accept() read() read() write() close() close() if (newsd=accept (sd,(struct sockaddr *) &client, sizeof(client)) < 0) { printf(“Error en el accept”); exit(-1); } /* transferir datos sobre newsd */ …. /* cerrar newsd */ } /* fin for */ /* cerrar sd */ } /* fin main */ 54 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Transferencia de datos con streams Una vez establecida la conexión usando sockets stream, ambos extremos puede transferir datos Envío: int write(int sd, char *mem, int long); int send(int sd, const void *mem, size_t long, int flags); Devuelve el número de bytes enviados o –1 si error El cuarto parámetro flags permite especificar opciones de envío (man send) 0 si no opciones MSG_OOB|MSG_DONTWAIT|MSG_DONTROUTE Es importante comprobar siempre el valor que devuelven estas llamadas: pueden no transferirse todos los datos 55 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Transferencia de datos con streams La recepción es una llamada bloqueante (síncrona) Recepción: int read(int sd, char *mem, int long); int recv(int sd, void *buf, size_t long, int flags); Devuelve el número de bytes recibidos o –1 si error El cuarto parámetro flags permite especificar opciones de recepción (man recv) 0 si no opciones MSG_OOB|MSG_PEEK|MSG_DONTROUTE Es importante comprobar siempre el valor que devuelven estas llamadas: pueden no transferirse todos los datos. 56 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo VII: Transferencia de datos con streams Función que envía un bloque de datos con reintentos: int enviar(int socket, char *mensaje, int longitud) { int r; int l = longitud; do { r = write(socket, mensaje, l); l = l – r; mensaje = mensaje + r; } while ((l>0) && (r>=0)); if (r < 0) return (-1); else return(0); /* fallo */ } 57 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Transferencia de datos con datagramas No hay conexión real Para usar un socket para transferir datos basta con: Crearlo (socket) Asignarle una dirección (bind) Si no se le asigna dirección, lo hará el sistema de manera transparente Envío: int sendto(int sd, char *buffer, int long, int flags, struct sockaddr *dir, int addrlen) Devuelve el número de bytes enviados o –1 si error Argumentos: sd descriptor de socket buffer puntero a los datos a enviar long la longitud de los datos flags opciones de envío (man sendto) dir dirección del socket remoto addrelnla longitud de la dirección 58 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Transferencia de datos con datagramas Recepción: int recvfrom(int sd, char *buffer, int long, int flags, struct sockaddr *dir, int addrlen) Devuelve el número de bytes recibidos o –1 si error Argumentos: sd descriptor de socket buffer puntero a los datos a enviar long la longitud de los datos flags opciones de recepción (man recvfrom) dir dirección del socket del cliente addrlenla longitud de la dirección Es importante comprobar siempre el valor que devuelven estas llamadas: pueden no transferirse todos los datos. 59 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Cerrar un socket (close) Se usa close para cerrar ambos tipos de sockets (stream y datagrama) int close(int sd); Si el socket es de tipo stream, cierra la conexión en ambos sentidos Devuelve –1 si error Se puede cerrar un único extremo: int shutdown(int sd, int modo); sd descriptor devuelto por socket modo SHUT_RD, SHUT_RW o SHUT_RDWR Devuelve –1 si error 60 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Conexión con TCP Servidor (host-A, 22) (tcp, host-A, 22, -, -) 61 cliente (host-B, 1500) (tcp, host-B, 1500, -, -) ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Conexión con TCP Servidor (host-A, 22) accept() 62 (tcp, host-A, 22, -, -) cliente (host-B, 1500) (tcp, host-B, 1500, -, -) ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Conexión con TCP Servidor (host-A, 22) accept() 63 (tcp, host-A, 22, -, -) cliente (host-B, 1500) connect() (tcp, host-B, 1500, -, -) ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Conexión con TCP Servidor (host-A, 22) accept() (tcp, host-A, 22, -, -) cliente (host-B, 1500) connect() (tcp, host-B, 1500, -, -) Nuevo descriptor de socket fork() (tcp, host-A, 22, host-B, 1500) 64 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Conexión con TCP Servidor (host-A, 22) cliente (host-B, 1500) (tcp, host-A, 22, -, -) (tcp, host-B, 1500, host-A, 22) Conexión (tcp, host-A, 22, host-B, 1500) 65 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Conexión con TCP Servidor (host-A, 22) accept() cliente (host-B, 1500) (tcp, host-A, 22, -, -) (tcp, host-B, 1500, host-A, 22) Conexión (tcp, host-A, 22, host-B, 1500) 66 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Conexión con TCP Servidor (host-A, 22) accept() cliente (host-B, 1500) (tcp, host-A, 22, -, -) (tcp, host-B, 1500, host-A, 22) Conexión (tcp, host-A, 22, host-B, 1500) cliente (host-C, 4000) (tcp, host-C, 4000, -, -) 67 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Conexión con TCP Servidor (host-A, 22) accept() cliente (host-B, 1500) (tcp, host-A, 22, -, -) (tcp, host-B, 1500, host-A, 22) connect() Conexión (tcp, host-A, 22, host-B, 1500) cliente (host-C, 4000) (tcp, host-C, 4000, -, -) 68 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Conexión con TCP Servidor (host-A, 22) accept() cliente (host-B, 1500) (tcp, host-A, 22, -, -) (tcp, host-B, 1500, host-A, 22) Conexión (tcp, host-A, 22, host-B, 1500) Nuevo descriptor de socket fork() cliente (host-C, 4000) (tcp, host-C, 4000, -, -) (tcp, host-A, 22, host-C, 4000) 69 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Conexión con TCP Servidor (host-A, 22) cliente (host-B, 1500) (tcp, host-A, 22, -, -) (tcp, host-B, 1500, host-A, 22) Conexión (tcp, host-A, 22, host-B, 1500) cliente (host-C, 4000) Conexión (tcp, host-C, 4000, host-A, 22) (tcp, host-A, 22, host-C, 4000) 70 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Configuración de opciones Existen varios niveles dependiendo del protocolo afectado como parámetro SOL_SOCKET: opciones independientes del protocolo IPPROTO_TCP: nivel de protocolo TCP IPPTOTO_IP: nivel de protocolo IP Consultar opciones asociadas a un socket int getsockopt (int sd, int nivel, int opc, char *val, int *long) Modificar las opciones asociadas a un socket int setsockopt (int sd, int nivel, int opc, char *val, int long) Ejemplos (nivel SOL_SOCKET): SO_REUSEADDR: 71 permite reutilizar direcciones ARCOS @ UC3M 2012-2013 Sistemas Distribuidos ¿Por qué utilizar SO_REUSEADDR? TCP mantiene las conexiones bloqueadas durante un cierto tiempo (TIME_WAIT) La conexión ya ha sido cerrada y no puede utilizarse, pero todavía no se han eliminado las tablas internas asociadas por si permanecen todavía segmentos en tránsito en la red int val = 1; setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(int)); 72 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos SO_RCVBUF, SO_SNDBUF Buffer de envío y recepción Fijar el tamaño del buffer de envío: int size = 16384; err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&size, (int)sizeof(size)); Conocer el tamaño del buffer de envío: int size; err = getsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&size,(int)sizeof(size)); printf(“%d\n”, size) 73 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos TCP_NODELAY Envío inmediato (sin intentar agrupar mensajes relativamente juntos en el tiempo) int option = 1; rc = setsockopt(s, 74 IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)); ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets de Java El paquete java.net de Java permite crear sockets TCP/IP Clases para sockets datagrama: DatagramSocket DatagramPacket Clases para sockets stream: ServerSocket Socket 75 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets datagrama DatagramPacket: Implementa un objeto que permite enviar o recibir paquetes Constructor: DatagramPacket Métodos: getAddress, getPort, ... http://download.oracle.com/javase/6/docs/api/java/net/DatagramPac ket.html DatagramSocket: Implementa un socket que se puede utilizar para enviar o recibir datagramas. Constructor: DatagramSocket Métodos: send, receive, close, setSoTimetout, getSoTimeout,... http://download.oracle.com/javase/6/docs/api/java/net/DatagramSoc ket.html 76 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets datagrama Proceso emisor Proceso receptor Vector de bytes Vector de bytes Dirección del receptor Objeto DatagramPacket Objeto DatagramPacket send receive Objeto DatagramSocket Objeto DatagramSocket Referencia a objeto Flujo de datos 77 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Sockets stream La clase socket implementa un socket stream Socket(InetAddress dirección, int puerto) OutputStream getOutputStream() flush InputStream getInputStream() void setSoTimeout(int tiempo_de_espera) http://download.oracle.com/javase/6/docs/api/java/net/Socket.html La clase ServerSocket implementa un socket a utilizar en los servidores para esperar la conexiones de los clientes socket accept() void close() void setSoTimeout(int tiempo_de_espera) http://download.oracle.com/javase/6/docs/api/java/net/ServerSock et.html 78 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo XI: Modelo de comunicación Servidor Cliente socket(host, puerto) 79 ServerSocket(puerto); accept(); OutputStream InputStream InputStream OutputStream close() close() ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Guía de diseño de aplicaciones clienteservidor Modelo de comunicación: conexión/no conexión Servidor secuencial/concurrente Problemas de concurrencia Comunicación síncrona/asíncrona Localización: Dirección IP y puerto en destino Formato de los datos Orden de los bytes: big-endian/little-endian Opciones de los sockets Protocolo de servicio Fiabilidad Gestión de errores (UDP) 80 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Comparación de protocolos IP UDP TCP ¿Orientado a conexión? No No Si ¿Límite entre mensajes? Si Si No ¿Ack? No No Si ¿Timeout y retransmisión? No No Si ¿Detección de duplicación? No No Si ¿Secuenciamiento? No No Si ¿Flujo de control? No No Si 81 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Modelo de servidor secuencial El servidor sirve las peticiones de forma secuencial Mientras está atendiendo a un cliente no puede aceptar peticiones de más clientes petición servidor Cliente respuesta 82 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo VIII: Programar un servidor y cliente en TCP Máquina A cliente Máquina B sumar(5,2) servidor 5+2 NÚCLEO Resultado = 7 NÚCLEO RED 83 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo VIII: Modelo de comunicación Proceso servidor socket() Proceso cliente bind() listen() socket() Conexión connect() write() Petición Respuesta 84 accept() read() read() write() close() close() ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Proceso servidor socket() Proceso cliente bind() Ejemplo VIII: Servidor TCP #include <sys/types.h> #include <sys/socket.h> void main(int argc, char *argv[]) { struct sockaddr_in server_addr, int sd, sc; int size, val; int size; int num[2], res; listen() socket() Conexión connect() write() Petición Respuesta accept() read() read() write() close() close() client_addr; if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))<0) printf (“SERVER: Error en el socket”); 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)); 85 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Proceso servidor socket() Proceso cliente bind() Ejemplo VIII: Servidor TCP Conexión connect() write() listen(sd, 5); size = sizeof(client_addr); listen() socket() Petición Respuesta accept() read() read() write() close() close() while (1) { printf("esperando conexion\n"); sc = accept(sd, (struct sockaddr *)&client_addr,&size); read ( sc, (char *) num, 2 *sizeof(int)); // recibe la petición res = num[0] + num[1]; // procesa la petición write(sc, &res, sizeof(int)); // envía el resultado close(sc); // cierra la conexión (sc) } close (sd); exit(0); } /*fin main */ 86 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Proceso servidor socket() Proceso cliente bind() Ejemplo VIII: Cliente TCP #include <sys/types.h> #include <sys/socket.h> listen() socket() Conexión connect() write() Petición Respuesta accept() read() read() write() close() close() void main(int argc, char **argv) // en argv[1] == servidor { int sd; struct sockaddr_in server_addr; struct hostent *hp; int num[2], res; if (argc != 2){ printf("Uso: cliente <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); 87 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Proceso servidor socket() Proceso cliente bind() Ejemplo VIII: Cliente TCP listen() socket() Conexión connect() write() Petición Respuesta read() // se establece la conexión connect(sd, (struct sockaddr *) &server_addr, sizeof(server_addr)); close() accept() read() write() close() num[0]=5; num[1]=2; write(sd, (char *) num, 2 *sizeof(int)); // envía la petición read(sd, &res, sizeof(int)); // recibe la respuesta printf("Resultado es %d \n", res); close (sd); exit(0); } /* fin main */ 88 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo IX: Programar un servidor y cliente en UDP Máquina A cliente Máquina B sumar(5,2) servidor 5+2 NÚCLEO Resultado = 7 NÚCLEO RED 89 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo IX: Modelo de comunicación Proceso servidor socket() Proceso cliente bind() socket() Petición sendto() recvfrom() Respuesta recvfrom() close() 90 sendto() close() ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo IX: Servidor UDP #include <sys/types.h> #include <sys/socket.h> Proceso servidor socket() Proceso cliente bind() socket() Petición sendto() recvfrom() Respuesta recvfrom() close() sendto() close() void main(void) { int num[2]; 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)); 91 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Proceso servidor Ejemplo IX: Servidor UDP socket() Proceso cliente bind() socket() Petición sendto() recvfrom() Respuesta clilen = sizeof(client_addr); recvfrom() close() sendto() close() while (1) { recvfrom(s, (char *) num, 2* sizeof(int), 0, (struct sockaddr *)&client_addr, &clilen); res = num[0] + num[1]; sendto(s, (char *)&res, sizeof(int), 0, (struct sockaddr *)&client_addr, clilen); } } /* fin main */ 92 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo IX: Cliente UDP void main(int argc, char *argv[]) { struct sockaddr_in server_addr, client_addr; struct hostent *hp; int s, num[2], res; Proceso servidor socket() Proceso cliente bind() socket() Petición sendto() recvfrom() Respuesta recvfrom() close() sendto() close() 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); 93 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo IX: Cliente UDP 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); Proceso servidor socket() Proceso cliente bind() socket() Petición sendto() recvfrom() Respuesta recvfrom() close() sendto() close() bind (s, (struct sockaddr *)&client_addr, sizeof(client_addr)); num[0] = 2; num[1] = 5; sendto(s, (char *)num, 2 * sizeof(int), 0, (struct sockaddr *) &server_addr, sizeof(server_addr)); recvfrom(s, (char *)&res, sizeof(int), 0, NULL, NULL); printf("2 + 5 = %d\n", res); close(s); } 94 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Problemas de los ejemplos anteriores Comprobación de errores. Muy importante Problemas en la transferencia de los datos Ordenamiento de los bytes ¿Qué ocurre si el cliente es little-endian y el servidor big-endian? Hay que resolver el problema de la representación de los datos. Una posibilidad es utilizar las funciones: u_long htonl(u_long hostlong) u_short htons(u_short hostshort) u_long ntohl(u_long netlong) u_short ntohs(u_short netshort) Definir el formato de representación e intercambio de datos Los datos que se envian a la red deben estar en Network Byte Order Los datos que se reciben de la red deben estar en Host Byte Order 95 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo X: Programar un servidor y cliente usando sockets datagramas de Java Máquina A cliente Máquina B sumar(5,2) servidor 5+2 NÚCLEO Resultado = 7 NÚCLEO RED 96 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo X: Cliente (datagramas) import java.lang.* ; import java.io.* ; import java.net.* ; import java.util.* ; public class client{ public static void main ( String [] args) { byte bsend[] = new byte[100]; byte brecv[] = new byte[100]; InetAddress server_addr = null; DatagramSocket s = null; DatagramPacket in = null; DatagramPacket out = null; int res; int num[] = new int[2]; if (args.length != 1) { System.out.println("Uso: cliente <host>"); System.exit(0); } 97 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo X: Cliente (datagramas) try { // se crea el socket del cliente s = new DatagramSocket(); // direción del servidor server_addr = InetAddress.getByName(args[0]); num[0] = 2; num[1] = 5; // empaquetar los datos. ByteArrayOutputStream baos = new ByteArrayOutputStream() ; ObjectOutputStream dos = new ObjectOutputStream(baos); dos.writeObject(num); bsend = baos.toByteArray() ; // se obtiene el buffer (datagrama) // un único envio out = new DatagramPacket (bsend, bsend.length, server_addr, 2500); s.send(out); 98 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo X: Cliente (datagramas) // se recibe el datagrama de respuesta in = new DatagramPacket (brecv, 100); s.receive(in); // se obtiene el buffer brecv = in.getData(); // se desempaqueta ByteArrayInputStream bais = new ByteArrayInputStream(brecv) ; DataInputStream dis = new DataInputStream(bais); res = dis.readInt(); System.out.println("Datos recibidos " + res); } catch (Exception e) { System.err.println("<<<<<excepcion " + e.toString() ); e.printStackTrace() ; } } } 99 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo X: Servidor (datagramas) import java.lang.* ; import java.io.* ; import java.net.* ; import java.util.* ; public class servidor { public static void main ( String [] args) { DatagramSocket s = null; DatagramPacket in, out; InetAddress client_addr = null; int client_port; byte brecv[] = new byte[100]; byte bsend[] = new byte[100]; int num[], res; try s { = new DatagramSocket(2500); in = new DatagramPacket(brecv, 100); // paquete para recibir la solicitud 100 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo X: Servidor (datagramas) while (true) { s.receive(in); //esperamos a recibir // obtener datos brecv = in.getData(); client_addr = in.getAddress(); client_port = in.getPort(); // desempaquetar los datos ByteArrayInputStream bais = new ByteArrayInputStream(brecv); ObjectInputStream dis = new ObjectInputStream(bais); num = (int[])dis.readObject(); res = num[0] + num[1]; 101 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo X: Servidor (datagramas) ByteArrayOutputStream baos = DataOutputStream dos = new ByteArrayOutputStream(); new DataOutputStream(baos); dos.writeInt(res); bsend = baos.toByteArray(); out = new DatagramPacket ( bsend, bsend.length,client_addr, client_port); s.send(out); } } catch(Exception e) { System.err.println("excepcion " + e.toString() ); e.printStackTrace() ; } } } 102 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo XI: Programar un servidor y cliente usando sockets stream de Java Máquina A cliente Máquina B sumar(5,2) servidor 5+2 NÚCLEO Resultado = 7 NÚCLEO RED 103 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo XI: Servidor stream import import import import java.lang.* ; java.io.* ; java.net.* ; java.util.* ; public class servidor { public static void main ( String [] args) { ServerSocket serverAddr = null; Socket sc = null; int num[] ; // petición int res; try { serverAddr = new ServerSocket(2500); } catch (Exception e){ System.err.println("Error creando socket"); } 104 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo XI: Servidor stream while (true){ try { sc = serverAddr.accept(); // esperando conexión InputStream istream = sc.getInputStream(); ObjectInput in = new ObjectInputStream(istream); num = (int[]) in.readObject(); res = num[0] + num[1]; DataOutputStream ostream = new DataOutputStream(sc.getOutputStream()); ostream.writeInt(res); ostream.flush(); sc.close(); } catch(Exception e) { System.err.println("excepcion " + e.toString() ); e.printStackTrace() ; } } } } 105 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo XI: Cliente streams import import import import java.lang.* ; java.io.* ; java.net.* ; java.util.* ; public class client { public static void main ( String [] args) { int res; int num[] = new int[2]; if (args.length != 1) { System.out.println("Uso: cliente <host>"); System.exit(0); } try { // se crea la conexión String host = args[0]; Socket sc = new Socket(host, 2500); // conexión 106 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Ejemplo XI: Cliente stream OutputStream ostream = sc.getOutputStream(); ObjectOutput s = new ObjectOutputStream(ostream); DataInputStream istream = new DataInputStream(sc.getInputStream()); num[0] = 5; num[1] = 2; //prepara la petición s.writeObject(num); s.flush(); res = istream.readInt(); sc.close(); System.out.println("La suma es " + res); } catch (Exception e){ System.err.println("excepcion " + e.toString() ); e.printStackTrace() ; } } } 107 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Modelo de servidor concurrente El servidor crea un hijo que atiende la petición y envía la respuesta al cliente Se pueden atender múltiples peticiones de forma concurrente petición servidor Cliente Crea un proceso hijo respuesta Proceso hijo 108 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Servidores concurrentes con sockets stream Proceso servidor socket() Proceso cliente bind() listen() socket() Abrir conexión connect() accept() Crear proceso hijo Petición write() read() close() 109 read() Respuesta write() close() ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Modelo de comunicación con sockets datagrama Proceso servidor socket() Proceso cliente bind() socket() Petición sendto() Respuesta recvfrom() close() 110 recvfrom() Crear proceso hijo sendto() close() ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Tipos de servidores concurrentes Un proceso servidor concurrente puede crear dos tipos de procesos: Procesos convencionales (fork) Procesos ligeros (threads) 111 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Procesos concurrentes con fork El servidor crea un socket s y le asocia una dirección El cuerpo principal del servidor es: for(;;) { sd = accept(s, (struct sockaddr *)& &cliente, &len); /* El hijo hereda el descriptor de socket */ pid = fork(); if (pid == -1) printf(“Imposible crear mas hijos \n”); else if (pid == 0)/* proceso hijo */ { close (s); tratar_peticion(sd); close(sd); exit(0); } close(sd); /* el padre */ } 112 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Procesos concurrentes con fork En el modelo anterior el proceso padre no espera la terminación de los procesos hijos con wait Los procesos hijos cuando mueren quedan en estado zombie (no desaparecen del sistema) Para que los procesos hijos no queden zombies se puede ejecutar en el padre (sólo para UNIX System V): signal(SIGCHLD, SIG_IGN); 113 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Servidores concurrentes con P. ligeros petcición servidor Cliente Crea thread de servicio respuesta Thread de servicio 114 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Procesos concurrentes con threads El servidor crea un socket s y le asocia una dirección El cuerpo principal del servidor es: pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); for(;;) { sd = accept(s, (struct sockaddr *)& &cliente, &len); pthread_create(&thid, &attr, tratar_peticion, &sd); } La función que ejecuta el proceso ligero es: void tratar_peticion(int * s) { int s_local; s_local = *s; /* tratar la petición utilizando el descriptor de s_local */ close(s_local); pthread_exit(NULL); } ¿Es correcta esta solución? 115 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Necesario sincronización La solución anterior es incorrecta ya que los procesos padre e hijo compiten por el acceso al descriptor (sd) devuelto por accept El proceso ligero hijo creado podría usar sd en tratar_petición mientras que un nuevo sd es asignado en accept Condiciones de carrera Necesario sincronizar las acciones con mutex y variables condicionales En el proceso servidor principal En los procesos ligeros hijos 116 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Necesario sincronización El proceso ligero principal debe ejecutar: for(;;) { sd = accept(s, (struct sockaddr *) &cliente, &len); pthread_create(&thid, &attr, tratar_peticion, &sd); /* esperar a que el hijo copie el descriptor */ pthread_mutex_lock(&m); while(busy == TRUE) pthread_cond_wait(&m, &c); busy = TRUE; pthread_mutex_unlock(&m); } 117 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Necesario sincronización El proceso ligero hijo debe ejecutar: void tratar_peticion(int * s) { int s_local; pthread_mutex_lock(&m); s_local = *s; busy = FALSE; pthread_cond_signal(&c); pthread_mutex_unlock(&m); /* tratar la petición utilizando el descriptor s_local */ pthread_exit(NULL); } 118 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Servidor concurrente en Java (streams) while (true){ try { Socket cliente = serverAddr.accept(); new TratarPeticion(cliente).start(); } catch(Exception e) { System.err.println("excepcion " + e.toString() ); e.printStackTrace() ; } } } } 119 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Servidor concurrente en Java (streams) class TratarPeticion extend Thread { private Socket sc; TratarPeticion(Socket s) { sc = s; } public void run() { // TODO: código del cliente } 120 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Bibliografía y ejemplos Ejemplos de programas usando sockets: Ejemplo de sockets Ejemplo de uso de sockets en Java http://www.php-es.com/ref.sockets.html Sockets en Java Programas de ejemplos de sockets y RPC 121 ARCOS @ UC3M 2012-2013 Sistemas Distribuidos Tema 5 Comunicación con sockets Grupo ARCOS Sistemas Distribuidos Grado en Ingeniería Informática Universidad Carlos III de Madrid