Sistemas Distribuidos
Ingeniería del Software
EUITI – UPM
Índice
RED “Retransmisión” partido N posibles “clientes” que se conectan al servidor para ver el partido Servidor, en el quejuegan los dos jugadores con el mismo teclado
Sockets
1981 BSD 4.2 de Unix Socket = extremo en lacomunicación bidireccional de 2 procesos (IP y puerto)
Abstracción de acceso a la capa
de transporte
Interfaz de programación mas
utilizada en Internet:
– Esta siendo estandarizada en POSIX (1003.1g – WinSockets – Clase de Java
Sockets servidor-cliente
Servidor Cliente Se crea el socket de conexion Se le asigna una direccion y un puerto y se pone a la escucha El socket de conexión se queda bloqueado a la espera “Aceptando una conexión” socket() bind() listen() accept() Se crea el socket de conexión y comunicación (es el mismo) Se conecta a la direccion del servidor socket() connect()Comunicacion Comunicacion send()
recv() send()
recv()
TCP/IP
Cuando el cliente se conecta al socket de conexión que esta “Aceptando”, este devuelve un socket de conexión que es con el que se realiza la comunicación
Sockets POSIX
Dominios de comunicación
Tipos de sockets
Direcciones de sockets
Creacion de un socket
Asignacion de direcciones
Solicitud de conexión
Preparar para aceptar conexiones
Aceptar una conexión
Transferencia de datos
Dominios de
comunicación
Un dominio es una familia de protocolos
Un socket esta asociado a 1 y solo 1 dominio
desde su creacion
Solo se pueden comunicar sockets del mismo
dominio
Dominios
– PF_UNIX : dentro de la misma computadora – PF_INET: usando protocolos TCP/IP
Los servicios de sockets son independientes
Tipos de sockets
2 tipos de sockets que determinan el estilo de
comunicación
– Stream (SOCK_STREAM)
Orientado a conexión
Fiable, se asegura el orden de llegada. Flujo de bytes, sin separacion entre mensajes
Si PF_INET (dominio internet) corresponde con el protocolo TCP
– Datagram (SOCK_DGRAM)
Sin conexión
No fiable, no asegura orden de entrega Mantiene separacion entre mensajes Si PF_INET, se corresponde con UDP
Ademas socket Raw (SOCK_RAW), que permite
acceso a protocolo IP
Direcciones de sockets
Cada socket debe tener asignada una
dirección única
2 funciones
– Asignar una dirección local a un socket (bind) – Especificar una dirección remota (connect)
Estructura generica struct sockaddr, cada
dominio usa una especifica
– PF_UNIX (struct sockaddr_un)– Direcciones en PF_INET (struct sockaddr_in) – El usuario debe hacer el casting para llamar a las
Direcciones sockets
Una direccion IP – Decimal-punto 138.100.100.1 – Dominio-punto elai.upm.es – se almacena en: struct in_addr char* inet_ntoa(struct in_addr in);
Socket se direcciona por el host (32bits) y el puerto
(16 bits)
Estructura struct sockaddr_in
– Debe iniciarse a cero
– sin_family: dominio AF_INET
– sin_port: numero de puerto, generalmente con htons(#) – sin_addr: direccion del host (INADDR_ANY)
Direcciones de sockets
int gethostname(char* name, int namelen);
struct hostent* gethostbyname(char* str)
– Convierte una notacion dominio-punto a una estructura de datos
char* name; //nombre de la maquina
char** h_addr_list; //Lista de direcciones, si se desea
ver, copiar los datos a una estructura in_addr, y hacer inet_ntoa(in_addr);
Direcciones de sockets
En TCP/IP se usa el formato big-endian,
contrario a maquinas Intel (little-endian)
Es necesario traducir el formato entre el
computador y TCP/IP
– u_long htonl(u_long hostlong); – u_short htons(u_short hostshort); – u_long ntohl(u_long netlong); – u_short ntohs(u_short netshort);
Solo necesario para informacion que deba
ser entendida por TCP/IP y por una
computadora no little-endian
Creacion de socket
int socket(int dominio, int tipo, int
protocolo);
– Crea un socket, devolviendo un descriptor de archivo
– Dominio: PF_UNIX, PF_INET
– Tipo: SOCK_STREAM, SOCK_DGRAM – Protocolo: dependiente del dominio y tipo
0 elige el mas adecuado Especificados /etc/protocols
Asignacion de direcciones
(servidor)
int bind(int sd,struct sockaddr* dir, int long)
– sd: descriptor del socket
– dir:direccion a asignar (cast de sockaddr_in o sockaddr_un)
– long: longitud de la direccion (sizeof) – Devuelve 0 o -1 en caso de error
Se utiliza para servidores tipicamente, mientras que
en clientes no (se le asigna automaticamente un puerto efimero en su primera utilizacion)
Direcciones en dominio PF_INET
– Puertos en rango 0-65535 Reservados 0-1024. Si es 0, el sistema escoge uno.
– Host: una direccion local IP
INADDR_ANY: Escoge cualquiera de la maquina.
Preparar para aceptar
conexiones (servidor)
int listen (int sd, int backlog)
– sd: descriptor devuelto por socket()
– backlog: el numero maximo de peticiones
pendientes que se encolara (5)
Realizada en el servidor despues de
socket() y bind()
Hace que el socket quede preparado
Aceptar conexion
(servidor)
int accept(int sd, struct sockaddr* dir, int* long)
– sd: descriptor devuelto por socket() (socket del servidor)
– dir: direccion del socket del cliente devuelta – long: parametro valor-resultado
Antes de la llamada: tamaño de “dir”
Despues de la llamada: tamaño de la direccion del cliente
que se devuelve
Realizada en el servidor stream, despues
de socket(), bind() y listen()
Aceptar conexion
(servidor)
accept() bloquea hasta que se produce la
conexión del cliente.
accept() devuelve un descriptor de socket,
el descriptor del cliente.
Se tienen 2 descriptores de socket:
– El original del servidor, para nuevas conexiones – El nuevo (del cliente) para enviar y recibir datos
Solicitud de conexion
(cliente)
Realizada en el cliente
int connect(int sd, struct sockaddr* dir, int long)
– sd: descriptor devuelto por socket()
– dir: direccion del socket remoto (IP y puerto) – long: longitud de la direccion (sizeof)
Si el socket no tiene direccion asignada, se le
asigna una automaticamente
Normalmente se usa con streams
0 en caso de éxito y -1 en caso de error
Obtener la direccion de
un socket
A partir del descriptor
– int getsockname(int s,struct sockaddr* dir,
int* long);
s: descriptor devuelto por socket() dir: direccion del socket devuelta long: parametro-valor resultado
El del otro extremo
– int getpeername(int sd, struct sockaddr*
dir, int* long)
Transferencia de datos
(streams)
Una vez realizada la conexión, ambos
extremos pueden transferir datos
Envio
– int write(int sd, char* a, int long);
Devuelve el numero de bytes enviados
– int send(…., int flags)
Recepcion:
– int read(int sd, char* mem, int long);
Devuelve el numero de bytes recibidos
– int recv(…., int flags)
Tanto en envio como en recepcion hay que
comprobar el valor de retorno.
Transferencia de datos
(streams)
int enviar(int s,char* msg,int l) { int r; int long=l; do { r=write(s,msg,long); msg+=r; long-=r; } while(long>0 && r>=0); if(r<0) return -1; else return 0; }
Transferencia datos
(DGRAM)
No hay conexión real
Para usar un socket para transferir:
– Crearlo: socket(…)
– Asignarle direccion: bind(…) (si no, lo hara
el sistema)
– Envio:
int sendto(int sd, char* mem, int long, int
flags, struct sockaddr* dir, int l)
– Devuelve el numero de bytes enviados – Dir: direccion del socket remoto
Cerrar un socket
Se usa “close” para cerrar ambos tipos
de sockets
Si el socket es de tipo stream,
entonces close cierra la conexión en
ambos sentidos
– Llamadas siguientes a write o read
fallaran devoviendo -1
Reutilización de
direcciones
bind() falla cuando se intenta reutilizar
un puerto
Ocupado durante 2-4 min
int on=1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
Conexiones multiples
Secuenciales
Conexiones secuenciales
Servidor Cliente Se crea el socket de conexion Se le asigna una direccion y un puerto y se pone a la escucha El socket de conexión se queda bloqueado a la espera “Aceptando una conexión” ComunicacionCierre del socket de comunicacion
Cierre del socket de conexion ¿Seguir aceptan do clientes ? SI NO Comunicacion Conexion Se crea el socket de conexión y comunicación Cierre Socket de conexion
Clase Socket
class Socket { public: Socket(); virtual ~Socket();int Connect(char ip[],int port); int InitServer(char ip[],int port); Socket Accept();
void Close();
int Send(char cad[],int length); int Receive(char cad[],int length); private:
Codigo
#include "Socket.h" int main() { Socket servidor; servidor.InitServer("127.0.0.1",12000); while(1) { Socket conn=servidor.Accept();//comunicacion, en este caso envio de 1 unico mensaje char cad[]="Hola mundo";
int length=sizeof(cad); conn.Send(cad,length); conn.Close(); } servidor.Close(); return 1; }
Conexiones simultaneas
ClienteN Comunicacion Conexion Se crea el socket de conexión y comunicación Cierre Servidor Cliente1 Se crea el socket de conexion Se le asigna una direccion y un puerto y se pone a la escucha El socket de conexión se queda bloqueado a la espera “Aceptando una conexión” Comunicación N ¿Seguir aceptan do clientes ? SI NO Comunicacion Conexion Se crea el socket de conexión y comunicación Cierre Comunicación 1 Socket de conexiónN Socket de conexión 1#include "Socket.h" int main() { Socket servidor; servidor.InitServer("127.0.0.1",12000); Socket conexiones[5]; for(i=0;i<5;i++) conexiones[i]=servidor.Accept();
//comunicacion, en este caso envio de 1 unico mensaje //se envia a los 5 clientes
char cad[]="Hola mundo"; int length=sizeof(cad); for(i=0;i<5;i++) conexiones[i].Send(cad,length); for(i=0;i<5;i++) conexiones[i].Close(); servidor.Close(); return 1; }
Sockets y concurrencia
accept() bloquea
recv() bloquea
Ejemplo bloqueo
void main() { float ref=3.0f; while(1) { //calculo continuo float dato=GetValorSensor(); error=ref-dato; float comando=K*error; EnviaComando(comando); } }Ejemplo GLUT
void glutMainLoop() { while(1) { if(pulsacion_teclado) glutInvocaMetodoTecladoUsuario(); if(hay_que_dibujar) glutInvocaMetodoDibujoUsuario(); if(tiempo_temporizador) glutInvocaMetodoTimerUsuario(); }Tareas a realizar
Enviar datos a todos los clientes
Permitir que se conecten nuevos
clientes (accept)
Recibir comandos control del jugador1
Recibir comandos control del jugador2
Animar la escena
Concurrencia
Programa servidor while(1) { //tareas //animacion //envio datos } while(1) { //accept() } while(1) { //recibir comandos Jugador1 } while(1) { //recibir comandos Jugador2 }Escenario tipico
cliente-servidor multihilo
Aplanamiento
Arquitectura Software.
Transparencia usuario de servicios.
Creacion de una Interfaz
Polimorfismo
Programacion con RPC
Suplentes
STUBS
– Localizan el servidor – Empaquetan parametros – Envian mensaje – Esperan y desempaquetan la respuestaEnlace dinamico (binding)
Enlace dinamico: permite localizar
objetos con nombre en un sistema
distribuido.
Tipos:
– No persistente
– Persistente
Introduccion a CORBA
RPC: remote procedurecall
Han evolucionado hacia
POO (CORBA, RMI)
Objetivo: la
transparencia.
– El cliente realiza la llamada empaqueta los argumentos, los envia y espera el resultado. – El servidor los extrae,
realiza la llamada local y envia el resultado de vuelta.
Corba
Common Object Request Broker Architecture (OMG)
– Especificacion de una arquitectura:
Independiente de la plataforma hardware y SO Independiente del lenguaje
Independiente de la red
– Automatizar:
Registro, localizacion y activacion de objetos:
– Name service
Aplanamiento y extraccion de parametros Gestion de llamadas
Envio de tramas Gestion de errores.
ORB
IDL
Definicion de interfaces (OO, clases) NO es un lenguaje de programacion
– Funciones
Estandar definido por CORBA (OMG)
– IDL C, C++, Java, ADA, Lisp, Python…
– IDL Stubs y skeletons
Soporta modules interfaces methods attributes inheritance arrays sequence
struct, enum, union, typedef consts exceptions No soporta No data members No pointers No constructors or destructors No overloaded methods No int data type
Contains parameter passing modes
Unions require a tag String type Sequence type
Dierent exception interface No templates
Ejemplo
interface XYTable { short Init(); short Done(); short PerformHoming(); //movement short SetVel(in float vel); short SetAcc(in float acc);short Move(in float x_mm,in float y_mm); short Stop();
short Continue(); //information
short GetCurrentPosition(out float x_mm,out float y_mm); short GetCurrentVel(out float vel);
short GetCurrentAcc(out float acc);
short GetInputs(out short inputsX,out short inputsY); short GetXYTableStatus(out short status);
short GetDriversStatus(out short DFX,out short DFY, out short STX,out short STY, out short UFX,out short UFY);
//Control short EmergencyStop(); short ResumeEmergencyStop(); short GetLastError(); };
Implementaciones
ACE-TAO
– http://www.cs.wustl.edu/~schmidt/TAO.html
Orbix IONA technologies
– www.iona.com
MICO
4 Ejercicio Examen Sept07
Realizar un programa cliente que se conecta
a un servidor de sockets (con comunicación
en forma de streams) ya existente en el
Instituto Nacional de Meteorología en la
dirección IP 123.123.123.123 en el puerto
3456 y que proporciona la predicción
meteorológica en forma de una cadena de
texto no mayor de 2000 caracteres cuando
se le envía la cadena “PREDICCION”. Dicho
programa (cliente) mostrara cuando se
ejecute la predicción y terminara a
continuación.
4 Feb 07
Servidor
1 unico
cliente
1 unica
peticion
int sock; float raiz_cuadrada(float a) { char peticion[100]; sprintf(peticion,"raiz %f",a); write(sock, peticion, strlen(peticion)); char respuesta[100]; read(sock, respuesta,10); float resultado; sscanf(respuesta,"%f",&resultado); return resultado; } void main(void) {struct sockaddr_in server_addr; struct hostent* hosten;
sock=socket(PF_INET,SOCK_STREAM,0); hosten=gethostbyname("192.168.1.111"); memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family=AF_INET; memcpy(&(server_addr.sin_addr),hosten->h_addr,hosten->h_length); server_addr.sin_port=htons(4200); if(0!=connect(sock,(struct sockaddr*)&server_addr,sizeof(server_addr))) { printf("Error en connect\n"); return; }
Jun07
Realizar un programa que actue de servidor remoto de 10 datos de tipo float
que se suponen adquiridos de 10 sensores.
El programa constara de 3 hilos:
– Un hilo secundario abrira un socket servidor que permitira la conexión de un unico cliente cada vez. Cuando dicho cliente se conecte le enviara constante y
repetidamente cada 100 ms la informacion de los 10 sensores. Si el cliente se desconecta, el socket vuelve a quedar a la espera de conexión de un nuevo cliente. – El segundo hilo secundario realiza la adquisición de los datos de los sensores tan
rapido como puede. Esta adquisición se simulara mediante un hipotetica funcion float ValorSensor(int i);
que devuelve el valor leido del sensor numero i, desde el 1 hasta el 10
– El hilo principal muestra cada segundo cuantas veces se han capturado las medidas de los sensores por segundo, asi como si el cliente esta conectado o no
Realizadas 145 medidas, cliente no conectado Realizadas 231 medidas, cliente no conectado Realizadas 212 medidas, cliente conectado
Nota: Los datos enviados por el socket deben corresponder a un unico
instante de tiempo o lectura de los mismos. Utilizar para ello los mecanismos de sincronizacion adecuados.
Jun08
Realizar un servidor concurrente que permita a
varios (cualquier numero) clientes conectarse simultaneamente y que provea a los mismos del servicio remoto bajo el paradigma de protocolo cliente-servidor
– float Sumar(float a, float b);
La peticion del cliente ira codificada como ASCII:
– “Sumar 0.3 3.5” – “3.8” Respuesta
Cada cliente conectado tendrá su propio hilo de
ejecucion.
El hilo principal se encarga de aceptar clientes.