Tema 5 Comunicación con sockets



Documentos relacionados
Sistemas Operativos Distribuidos

Sistemas Distribuidos. Sockets

Tema 3: COMUNICACIÓN ENTRE PROCESOS

Estructuras y funciones de programación de sockets.

BOLETIN 8 INDICE. ordenación de bytes. conversión de nombre y direcciones.

Sockets: funcionamiento y programación. Sockets tipo UNIX. MSc. Ivan A. Escobar

Cliente/Servidor en Java

ARQUITECTURA DE REDES Laboratorio

-> Todo socket viene definido por dos características fundamentales:

Estructuras y funciones de programación de sockets.

Práctica 1 Programación de Aplicaciones Distribuidas: Sockets UDP. Laboratorio de Comunicación de Datos ITT Telemática Septiembre 2011

Tema 4 Sockets: Un interfaz con TCP/IP

Introducción de Sockets en C.

Tema 4: Sockets: Un interfaz con TCP/IP

Diseño de aplicaciones distribuidas ÍNDICE

Mecanismos IPC: sockets

COMUNICACIÓN Sistemas Distribuidos

Migrando aplicaciones a IPv6

Programación con sockets

1_servicio_eco_stream_secuencial/eco_clie_tcp.c Tue Mar 09 09:57:

Desarrollo de Aplicaciones Distribuidas. Sockets. Daniel Avellaneda

Arquitecturas cliente/servidor

Redes de Computadores Nivel de Aplicación: Programación con sockets I

Adaptación de aplicaciones a IPv6

Paso de mensajes en Java

Ingeniería Técnica de Telecomunicación, esp. Telemática Universidad de Jaén

Clase de Sockets en lenguaje C. Prof. Ricardo González

Práctica 2 Programación de Aplicaciones Distribuidas: Sockets TCP. Laboratorio de Comunicación de Datos ITT Telemática 26 de Septiembre 2011

Sockets (TCP) Tema 2.- Nivel de aplicación en Internet

UNIVERSIDAD DE CANTABRIA DEPARTAMENTO DE INGENIERÍA DE COMUNICACIONES GRUPO DE INGENIERÍA TELEMÁTICA

Capítulo 5. Programación de aplicaciones de red

Arquitecturas Cliente/Servidor

Sockets. Los sockets son un mecanismo de comunicación entre procesos que se utiliza en Internet.

sockets Flujo (SOCK_STREAM) Comunicación bidireccional Confiable (entrega garantizada) Información ordenada en el destino Datagrama (SOCK_DGRAM)

Introducción a la programación con sockets en C

DESARROLLO DE APLICACIONES DISTRIBUIDAS. SOCKETS en UNIX

Desarrollo de Aplicativos con winsockets

Sistemas operativos: una visión aplicada. Capítulo 10 Introducción a los sistemas distribuidos

Tema 2. Comunicación entre procesos

Qué es un socket? Dominios de comunicación. Tipos de sockets en el dominio AF_INET. Sockets Stream. Sockets Datagram. Sockets Raw

Los sockets de Unix. Dr. Roberto Gómez Cárdenas ITESM-CEM. Dr. Roberto Gomez C. Diapo. No.

SOCKETS en Linux. Lic. Leonardo de - Matteis. Departamento de Ciencias e Ingeniería de la Computación Universidad Nacional del Sur 2011

EJEMPLOS PROGRAMACIÓN SOCKET - JAVA

Programación con Sockets

INTRODUCCIÓN A LA PROGRAMACIÓN CON SOCKETS. Celeste Campo Carlos García Rubio

Comunicación entre procesos: sockets udp. Jorge Iván Meza Martínez

Programación Básica de Sockets en Unix para Novatos

Características de un lenguaje ideal para robótica

Modem IBM Compatible. IBM Compatible. Ethernet IBM AS/400. Laser printer. Workstation. Mac II. El Interfaz. Socket. versión perliminar

ARQUITECTURA DE REDES Laboratorio PRÁCTICA 2: MANUAL DE SOCKETS EN C. Grado en Ingeniería Informática Curso 2014/15

Programación en red sobre TCP/IP Interface sockets

Tema II. Sockets. Desarrollo de Aplicaciones para Internet Curso Miguel Reboiro Jato

Programación C/S Básica

Sockets (UDP) Tema 2.- Nivel de aplicación en Internet

Federico Peinado

Problemas de Redes de Computadores. Conjunto de problemas 1

1.- FUNDAMENTOS FUNCIONAMIENTO GENÉRICO JAVA SOCKETS Creación de Streams de Entrada...7

UNIVERSIDADE DA CORUÑA Departamento de Tecnoloxías da Información e as Comunicacións LABORATORIO DE RC: TUTORIAL DE SOCKETS EN JAVA

SOCKET S. Alberto Castro Rojas

Transcripción:

Tema 5 Comunicación con sockets Grupo ARCOS 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

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

Sockets: introducción Aplicaciones/servicios RMI and RPC Sockets Aplanamiento (marshalling), representación externa de datos Protocolo de transporte UDP y TCP 4

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

Sockets UNIX Dominios de comunicación AF_UNIX AF_INET Tipos de sockets Stream (SOCK_STREAM) Datragrama (SOCK_DGRAM) Direcciones de sockets 6

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

Tipos de sockets Stream (SOCK_STREAM) Protocolo TCP Datagrama (SOCK_DGRAM) Protocolo UDP Raw (SOCK_RAW) Sockets sin protocolo de transporte 8

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

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

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

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

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

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

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

Encapsulación de un paquete TCP Datos 16

Encapsulación de un paquete TCP Datos Puerto Origen Puerto Destino Cabecera TCP Datos 17

Encapsulación de un paquete TCP Datos Puerto Origen Puerto Destino Protocolo =TCP IP Origen IP Destino Cabecera IP Cabecera TCP Cabecera TCP Datos Datos 18

Encapsulación de un paquete TCP Datos Puerto Origen Puerto Destino Protocolo =TCP IP Origen IP Destino Cabecera IP Cabecera TCP Cabecera TCP Datos Datos Tipo de trama = IP Dirección Eth. Origen Dirección Eth. Destino Cabecera Ethernet Cabecera IP Cabecera TCP Datos Cola Ethernet 19

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

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: #include <netinet/in.h> struct sockaddr_in { short u_short struct in_addr char }; dominio (AF_INET) puerto dirección del host sin_family; sin_port; sin_addr; sin_zero[8]; struct sockaddr_in family 2-byte port 4-byte Net ID, host ID unused 21

Direcciones de sockets en AF_UNIX La estructura struct sockaddr_un describe la dirección de un socket AF_LOCAL o AF_UNIX #include <sys/un.h> struct sockaddr_un { short sun_family; char sun_path[108]; }; struct sockaddr_un family Pathname (up to 108 bytes) 22

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

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 referencia al buffer donde se almacena el nombre longitud del buffer 24

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

Transformación de direcciones The McGraw-Hill 26

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

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

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

Estructura hostent The McGraw-Hill 30

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

Ejemplo IV: obtener la dirección de host en decimal-punto #include <netdb.h> #include <stdio.h> #include <string.h> main(int argc, const char **argv) { u_int addr; struct hostent *hp; char **p; struct in_addr in; char **q; 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

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

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

Ejemplo: Representación del 1 Big Endian MSB LSB Direcciones: Little Endian 0 0 0 1 n n+1 n+2 n+3 Dirección de crecimiento LSB MSB Direcciones: 1 0 0 0 n n+1 n+2 n+3 35 Dirección de crecimiento

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 1.2 7.3 Representación en el computador A -1.5 Desempaquetamiento de datos (unmarshalling) Conversión de los datos a su representación interna 10010111 0110010 36 Esto es una cadena 1.2 7.3 Representación en el computador B -1.5

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

Funciones de transformación The McGraw-Hill 38

Modelos de comunicación Sockets stream (SOCK_STREAM) Orientado a conexión TCP Sockets datagrama (SOCK_DGRAM) No orientado a conexión UDP 39

Modelo de comunicación con sockets stream Proceso servidor Proceso cliente socket() bind() socket() connect() Conexión listen() accept() write() read() Petición Respuesta read() write() close() close() 40

Modelo de comunicación con sockets datagrama Proceso servidor Proceso cliente socket() bind() socket() sendto() recvfrom() Petición Respuesta recvfrom() sendto() close() close() 41

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

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 AF_UNIX,AF_INET tipo SOCK_STREAM,SOCK_DGRAM protocolo 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

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

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

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 descriptor devuelto por socket dir dirección del socket devuelta long: 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 descriptor devuelto por socket dirección del socket remoto parámetro valor-resultado 46

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

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

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

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

Establecimiento de una conexión en TCP 51

Ejemplo VI: Establecimiento de conexión TCP (clientes) int main() { int sockfd; struct sockaddr_in server; Proceso cliente socket() Conexión connect() Petición write() Respuesta read() close() Proceso servidor socket() bind() listen() accept() read() write() 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

Ejemplo VI: Establecimiento de conexión TCP (servidores) Proceso cliente socket() Conexión connect() Proceso servidor socket() bind() listen() accept() int main() write() Petición read() { read() Respuesta write() int sd, newsd, size; close() close() 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

Ejemplo VI: continuación (servidores) Proceso cliente socket() Conexión connect() Proceso servidor socket() bind() listen() accept() listen(sd,5) for (;;) { 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 */ write() read() close() Petición Respuesta read() write() close() 54

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

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

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); /* fallo */ else return(0); 57

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

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

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

Conexión con TCP Servidor (host-a, 22) cliente (host-b, 1500) (tcp, host-a, 22, -, -) (tcp, host-b, 1500, -, -) 61

Conexión con TCP Servidor (host-a, 22) cliente (host-b, 1500) accept() (tcp, host-a, 22, -, -) (tcp, host-b, 1500, -, -) 62

Conexión con TCP Servidor cliente (host-a, 22) (host-b, 1500) accept() (tcp, host-a, 22, -, -) connect() (tcp, host-b, 1500, -, -) 63

Conexión con TCP Servidor cliente (host-a, 22) (host-b, 1500) accept() (tcp, host-a, 22, -, -) connect() (tcp, host-b, 1500, -, -) Nuevo descriptor de socket fork() (tcp, host-a, 22, host-b, 1500) 64

Conexión con TCP Servidor (host-a, 22) cliente (host-b, 1500) (tcp, host-a, 22, -, -) (tcp, host-b, 1500, host-a, 22) (tcp, host-a, 22, host-b, 1500) Conexión 65

Conexión con TCP Servidor (host-a, 22) cliente (host-b, 1500) accept() (tcp, host-a, 22, -, -) (tcp, host-b, 1500, host-a, 22) (tcp, host-a, 22, host-b, 1500) Conexión 66

Conexión con TCP Servidor (host-a, 22) cliente (host-b, 1500) accept() (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

Conexión con TCP Servidor (host-a, 22) cliente (host-b, 1500) accept() (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

Conexión con TCP Servidor (host-a, 22) cliente (host-b, 1500) accept() (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() (tcp, host-a, 22, host-c, 4000) cliente (host-c, 4000) (tcp, host-c, 4000, -, -) 69

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-a, 22, host-c, 4000) (tcp, host-c, 4000, host-a, 22) 70

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: permite reutilizar direcciones 71

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

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

TCP_NODELAY Envío inmediato (sin intentar agrupar mensajes relativamente juntos en el tiempo) int option = 1; rc = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)); 74

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

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

Sockets datagrama Proceso emisor Vector de bytes Proceso receptor Vector de bytes Dirección del receptor Objeto DatagramPacket Objeto DatagramPacket send Objeto DatagramSocket receive Objeto DatagramSocket Referencia a objeto Flujo de datos 77

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

Ejemplo XI: Modelo de comunicación Servidor Cliente ServerSocket(puerto); socket(host, puerto) accept(); OutputStream InputStream InputStream OutputStream close() close() 79

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

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

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 Cliente servidor respuesta 82

Ejemplo VIII: Programar un servidor y cliente en TCP Máquina A cliente sumar(5,2) Máquina B servidor 5+2 NÚCLEO Resultado = 7 NÚCLEO RED 83

Ejemplo VIII: Modelo de comunicación Proceso servidor Proceso cliente socket() bind() socket() connect() Conexión listen() accept() write() read() Petición Respuesta read() write() close() close() 84

Proceso servidor Ejemplo VIII: Servidor TCP #include <sys/types.h> #include <sys/socket.h> 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; if ((sd = socket(af_inet, SOCK_STREAM, IPPROTO_TCP))<0) printf ( SERVER: Error en el socket ); Proceso cliente socket() Conexión connect() Petición write() Respuesta read() close() socket() bind() listen() accept() read() write() close() 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

Proceso servidor Ejemplo VIII: Servidor TCP Proceso cliente socket() Conexión connect() socket() bind() listen() accept() listen(sd, 5); size = sizeof(client_addr); write() read() close() Petición Respuesta read() write() 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]; write(sc, &res, sizeof(int)); close(sc); // procesa la petición // envía el resultado // cierra la conexión (sc) close (sd); exit(0); } /*fin main */ 86

Proceso servidor Ejemplo VIII: Cliente TCP #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; 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); Proceso cliente socket() Conexión connect() Petición write() Respuesta read() close() socket() bind() listen() accept() read() write() close() 87

Proceso servidor Ejemplo VIII: Cliente TCP Proceso cliente socket() Conexión connect() socket() bind() listen() accept() write() Petición read() Respuesta read() // se establece la conexión close() connect(sd, (struct sockaddr *) &server_addr, sizeof(server_addr)); 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

Ejemplo IX: Programar un servidor y cliente en UDP Máquina A cliente sumar(5,2) Máquina B servidor 5+2 NÚCLEO Resultado = 7 NÚCLEO RED 89

Ejemplo IX: Modelo de comunicación Proceso servidor Proceso cliente socket() bind() socket() sendto() recvfrom() Petición Respuesta recvfrom() sendto() close() close() 90

Ejemplo IX: Servidor UDP #include <sys/types.h> #include <sys/socket.h> Proceso cliente Proceso servidor socket() bind() socket() Petición sendto() recvfrom() Respuesta recvfrom() sendto() close() 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

Ejemplo IX: Servidor UDP Proceso cliente socket() Proceso servidor socket() bind() clilen = sizeof(client_addr); sendto() recvfrom() Petición Respuesta recvfrom() sendto() close() 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

Ejemplo IX: Cliente UDP Proceso cliente socket() Proceso servidor socket() bind() void main(int argc, char *argv[]) { struct sockaddr_in server_addr, client_addr; struct hostent *hp; int s, num[2], res; sendto() recvfrom() close() Petición Respuesta recvfrom() 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

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 cliente Proceso servidor socket() bind() socket() Petición sendto() recvfrom() Respuesta recvfrom() sendto() close() 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

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

Ejemplo X: Programar un servidor y cliente usando sockets datagramas de Java Máquina A cliente NÚCLEO sumar(5,2) Resultado = 7 Máquina B servidor 5+2 NÚCLEO RED 96

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]; 97 if (args.length!= 1) { System.out.println("Uso: cliente <host>"); System.exit(0); }

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

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

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

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

Ejemplo X: Servidor (datagramas) ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = 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

Ejemplo XI: Programar un servidor y cliente usando sockets stream de Java Máquina A cliente NÚCLEO sumar(5,2) Resultado = 7 Máquina B servidor 5+2 NÚCLEO RED 103

Ejemplo XI: Servidor stream import java.lang.* ; import java.io.* ; import java.net.* ; import 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

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(); } } 105 } sc.close(); } catch(exception e) { System.err.println("excepcion " + e.tostring() ); e.printstacktrace() ; }

Ejemplo XI: Cliente streams import java.lang.* ; import java.io.* ; import java.net.* ; import 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

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

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 Cliente petición servidor Crea un proceso hijo respuesta Proceso hijo 108

Servidores concurrentes con sockets stream Proceso servidor Proceso cliente socket() bind() socket() listen() connect() Abrir conexión accept() Crear proceso hijo write() Petición read() read() Respuesta write() close() close() 109

Modelo de comunicación con sockets datagrama Proceso servidor Proceso cliente socket() bind() socket() sendto() recvfrom() Petición Respuesta recvfrom() Crear proceso hijo sendto() close() close() 110

Tipos de servidores concurrentes Un proceso servidor concurrente puede crear dos tipos de procesos: Procesos convencionales (fork) Procesos ligeros (threads) 111

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); } pid = fork(); /* El hijo hereda el descriptor de socket */ 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

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

Servidores concurrentes con P. ligeros petcición Cliente servidor Crea thread de servicio respuesta Thread de servicio 114

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

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

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

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

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

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

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

Tema 5 Comunicación con sockets Grupo ARCOS Grado en Ingeniería Informática Universidad Carlos III de Madrid