Tema 5 Comunicación con sockets - Arcos

Anuncio
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
Descargar