Direccionamiento Información válida para la identificación de elementos del sistema. Posibles receptores de un mensaje.
Mecanismos: Dirección dependiente de la localización: Por ejemplo: dirección máquina + dirección puerto local. No proporciona transparencia. Dirección independiente de la localización (dir. lógica): Facilita transparencia. Necesidad de proceso de localización: Mediante broadcast. Uso de un servidor de localización que mantiene relaciones entre direcciones lógicas y físicas. Uso de cache en clientes para evitar localización.
Comunicación en Grupo Se habilita por medio de: Variantes de protocolos de red: IP-multicast. Emulandola por medio de protocolos de alto nivel o por las aplicaciones.
El direccionamiento se realiza por medio de una dirección de grupo (grupo al que pertenecen todos los receptores).
Modelos de grupos: Grupo abierto. Grupo abierto controlado. Grupo cerrado.
Comunicación en Grupo Utilidad para los sistemas distribuidos: Ofrecer tolerancia a fallos basado en servicios replicados. Localizar objetos en sistemas distribuidos. Mejor rendimiento mediante datos replicados. Actualizaciones múltiples. Operaciones colectivas en cálculo paralelo.
Problemática: Comunicación fiable es difícil. Escalabilidad de las tecnologías (Internet con MBone). Gestión de grupos. Encaminamiento (Flooding, Spanning Tree, RPB, TRPB, RPM).
Ordenación en Comunicación en Grupo De acuerdo a las garantías de ofrecidas en la recepción de mensajes de grupo se tienen: Ordenación FIFO: Los mensajes de una fuente llegan a cada receptor en el orden que son enviados.
Ordenación Causal: Los mensajes enviados por dos emisores distintos so recibidos en el orden relativo en el que se han enviado.
Ordenación Total: Todos los mensajes (de varias fuentes) enviados a un grupo son recibidos en el mismo orden por todos los elementos.
Cliente-Servidor < Paso de Mensajes> Berkeley Sockets Java Sockets
Paso de Mensajes Los modelos de comunicación basados en cliente-servidor con paso de mensajes responden al esqueleto: CLIENTE msg Send(msg) Send(msg) msg SERVIDOR msg Receive(msg) Mensaje msg,reply; msg=< dato a trasmitir> send(msg); receive(reply); if(isOK(reply)) < operación correcto> else < error en operación> … Mensaje op,ack; receive(op); if(validOp(op)) ack=< operación OK> else ack=< operación ERROR> send(ack); …
Paso de Mensajes Cada pareja send-receive transmite un mensaje entre cliente y servidor. Por lo general de forma asíncrona. Habitualmente: Send no bloqueante. Receive bloqueante (pude hacerse no bloqueante).
Los mensajes intercambiados pueden ser: Mensajes de texto (por ejemplo: HTTP). Mensajes con formato (binarios).
Las aplicaciones definen el protocolo de comunicación: Petición-respuesta, recepción explícita, sin/con confirmación, …
Mensajes Texto Estructura del Mensaje: Cadenas de caracteres. Por ejemplo HTTP: GET //www.fi.upm.es HTTP/1.1
Envío del Mensaje: send(GET //www.fi.upm.es HTTP/1.1);
El emisor debe hacer un análisis de la cadena de caracteres transmitida.
Mensajes Binarios Estructura del Mensaje: struct mensaje_st { unsigned int msg_tipo; unsigned int msg_seq_id; unsigned char msg_data[1024]; }; Envío del Mensaje: struct mensaje_st confirm; confirm.msg_tipo=MSG_ACK; confirm.msg_seq_id=129;
send(confirm);
Formatos de Representación Para la transmisión de formatos binarios tanto emisor y receptor deben coincidir en la interpretación de los bytes transmitidos. Problemática: Tamaño de los datos numéricos. Ordenación de bytes. Formatos de texto: ASCII vs EBCDIC. Arquitectura little-endian Dato a enviar: 5 0 0 0 5 Valor: 0x224+0x216+0x28+5 Arquitectura big-endian Dato a recibido: 83.886.080 0 0 0 5 Valor: 5×224+0x216+0x28+0 0 0 0 5 0 1 2 3 3 2 1 0
Berkeley Sockets 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 punto final de comunicación (dirección IP y puerto).
Abstracción que: Ofrece interfaz de acceso a los servicios de red en el nivel de transporte. Representa un extremo de una comunicación bidireccional con una dirección asociada.
Berkeley Sockets Sujetos a proceso de estandarización dentro de POSIX (POSIX 1003.1g).
Actualmente: Disponibles en casi todos los sistemas UNIX. En prácticamente todos los sistemas operativos: WinSock: API de sockets de Windows. En Java como clase nativa.
Conceptos Básicos sobre Sockets Dominios de comunicación. Tipos de sockets. Direcciones de sockets. Creación de un socket. Asignación de direcciones. Solicitud de conexión. Preparar para aceptar conexiones. Aceptar una conexión. Transferencia de datos.
1.- Creación del socket 2.- Asignación de dirección 913367377 3.- Aceptación de conexión
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.
Algunos ejemplos: PF_UNIX (o PF_LOCAL): comunicación dentro de una máquina. PF_INET: comunicación usando protocolos TCP/IP.
Tipos de Sockets Stream (SOCK_STREAM): Orientado a conexión. Fiable, se asegura el orden de entrega de mensajes. No mantiene separación entre mensajes. Si PF_INET se corresponde con el protocolo TCP. Datagrama (SOCK_DGRAM): Sin conexión. No fiable, no se asegura el orden en la entrega. Mantiene la separación entre mensajes. Si PF_INET se corresponde con el protocolo UDP. Raw (SOCK_RAW): Permite el acceso a los protocolos internos como IP.
Direcciones de Sockets Cada socket debe tener asignada una dirección única. Dependientes del dominio. Las direcciones se usan para: Asignar una dirección local a un socket (bind). Especificar una dirección remota (connect o sendto).
Se utiliza la estructura genérica de dirección: struct sockaddr mi_dir; Cada dominio usa una estructura específica. Uso de cast en las llamadas. Direcciones en PF_INET (struct sockaddr_in). Direcciones en PF_UNIX (struct sockaddr_un).
Direcciones de Sockets en PF_INET Una dirección destino viene determinada por: Dirección del host: 32 bits. Puerto de servicio: 16 bits. Estructura struct sockaddr_in: Debe iniciarse a 0 (bzero). sin_family: dominio (AF_INET). sin_port: puerto. sin_addr: dirección del host. Una transmisión está caracterizada por cinco parámetros únicos: Dirección host y puerto origen. Dirección host y puerto destino. Protocolo de transporte (UDP o TCP).
Obtención de la Dirección del Host Usuarios manejan direcciones en forma de texto: decimal-punto: 138.100.8.100 dominio-punto: laurel.datsi.fi.upm.es
Conversión a binario desde decimal-punto: int inet_aton(char *str,struct in_addr *dir) str: contiene la cadena a convertir. dir: resultado de la conversión en formato de red. Conversión a binario desde dominio-punto: struct hostent *gethostbyname(char *str) str: cadena a convertir. Devuelve la estructura que describe al host.
Creación de un Socket La función socket crea uno nuevo: int socket(int dom,int tipo,int proto) Devuelve un descriptor de fichero (igual que un open de fichero). Dominio (dom): PF_XXX Tipo de socket (tipo): SOCK_XXX Protocolo (proto): Dependiente del dominio y del tipo: 0 elige el más adecuado. Especificados en /etc/protocols.
El socket creado no tiene dirección asignada.
Asignación de Direcciones La asignación de una dirección a un socket ya creado: int bind(int s,struct sockaddr* dir,int tam) Socket (s): Ya debe estar creado. Dirección a asignar (dir): Estructura dependiendo del dominio. Tamaño de la dirección (tam): sizeof().
Si no se asigna dirección (típico en clientes) se le asigna automáticamente (puerto efímero) en la su primera utilización (connect o sendto).
Asignación de Direcciones (PF_INET) Direcciones en dominio PF_INET Puertos en rango 0..65535. Reservados: 0..1023. Si se le indica el 0, el sistema elige uno. Host: una dirección IP de la máquina local. INADDR_ANY: elige cualquiera de la máquina. Si el puerto solicitado está ya asignado la función bind devuelve un valor negativo.
El espacio de puertos para streams (TCP) y datagramas (UDP) es independiente.
Solicitud de Conexión Realizada en el cliente por medio de la función: int connect(int s,struct sockaddr* d,int tam) Socket creado (s). Dirección del servidor (d). Tamaño de la dirección (tam).
Si el cliente no ha asignado dirección al socket, se le asigna una automáticamente.
Normalmente se usa con streams.
Preparar para Aceptar Conexiones Realizada en el servidor stream después de haber creado (socket) y reservado dirección (bind) para el socket: int listen(int sd, int baklog) Socket (sd): Descriptor de uso del socket. Tamaño del buffer (backlog): Número máximo de peticiones pendientes de aceptar que se encolarán (algunos manuales recomiendan 5)
Hace que el socket quede preparado para aceptar conexiones.
Aceptar una Conexión Realizada en el servidor stream después de haber preparado la conexión (listen): int accept(int s,struct sockaddr *d,int *tam) Socket (sd): Descriptor de uso del socket. Dirección del cliente (d): Dirección del socket del cliente devuelta. Tamaño de la dirección (tam): Parámetor valor-resultado Antes de la llamada: tamaño de dir Después de la llamada: tamaño de la dirección del cliente que se devuelve.
Aceptar una Conexión La semántica de la función accept es la siguiente: Cuando se produce la conexión, el servidor obtiene: La dirección del socket del cliente. Un nuevo descriptor (socket) 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. Idealmente se pueden plantear servidores multithread para servicio concurrente.
Otras Funcionalidades Obtener la dirección a partir de un descriptor: Dirección local: getsockname(). Dirección del socket en el otro extremo: getpeername(). Transformación de valores: De formato host a red: Enteros largos: htonl(). Enteros cortos: htons(). De formato de red a host: Enteros largos: ntohl(). Enteros cortos: ntohs(). Cerrar la conexión: Para cerrar ambos tipos de sockets: close(). Si el socket es de tipo stream cierra la conexión en ambos sentidos. Para cerrar un único extremo: shutdown().
Transferencia de Datos con Streams Envío: Puede usarse la llamada write sobre el descriptor de socket. int send(int s,char *mem,int tam,int flags) Devuelve el nº de bytes enviados. Recepción: Puede usarse la llamada read sobre el descriptor de socket. int recv(int s,char *mem,int tam,int flags) Devuelve el nº de bytes recibidos.
Los flags implican aspectos avanzado como enviar o recibir datos urgentes (out-of-band).
Escenario de Uso de Sockets streams Proceso cliente Proceso servidor socket() socket() bind() listen() accept() Posible Ejecución en Paralelo accept() connect() Abrir conexión close() Petición send()/write() Respuesta close() recv()/read() send()/write() recv()/read()
Transferencia de Datos con Datagramas Envío: int sendto(int s,char *mem,int tam, int flags,struct sockaddr *dir, int *tam) Recepción: int recvfrom(int s,char *mem,int tam, int flags,struct sockaddr *dir, int *tam) No se establece una conexión (connect/accept) previa. Para usar un socket para transferir basta con crear el socket y reservar la dirección (bind).
Escenario de Uso de Sockets Datagrama Proceso socket() bind() close() Petición sendto() Respuesta recvfrom() Proceso socket() bind() close() recvfrom() sendto()
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: getsockopt() Modificar opciones asociadas a un socket: setsockopt() Ejemplos (nivel SOL_SOCKET): SO_REUSEADDR: permite reutilizar direcciones
Sockets en Java Engloba en objetos cada una de las estructuras de la comunicación. Las funciones se tratan como métodos de dichos objetos: InetAddress Socket DatagramSocket ServerSocket Connection DatagramPacket
Define un nivel de abstracción mayor, proporcionando constructores que realizan parte del proceso de inicialización de los elementos.
Sockets en Java (Direccionamiento) Las direcciones de Internet se asocian a objetos de la clase InetAddress. Estos objetos se construyen en base a métodos estáticos de la clase:
static InetAddress getByName(String host) Obtiene una dirección IP en base al nombre (dominios o números). static InetAddress getLocalHost() Obtiene la dirección IP local.
Sockets en Java (UDP) La información a trasmitir se asocia a un objetos de la clase DatagramPacket. Estos objetos se construyen con un array de bytes a transmitir:
DatagramPacket(byte[] datos, int tam) Crea un datagrama para el vector de bytes a transmitir.
Adicionalmente se le puede pasar una dirección IP (InetAddress) y un puerto para indicar el destino de transmisión del paquete cuando se envíe.
Sockets en Java (UDP) La comunicación vía UDP se realiza por medio de objetos de la clase DatagramSocket. DatagramSocket(int puerto,InetAddress dir) Crea un socket UDP con un bind a la dirección y puerto indicados. Dirección y puerto son opcionales (se elige uno libre). void send(DatagramPacket paquete) Envía el datagrama a la dirección del paquete. void receive(DatagramPacket paquete) Se bloquea hasta la recepción del datagrama. Otros métodos: void close(): Cierra el socket. void setSoTimeout(int timeout): Define el tiempo de bloqueo en un receive().
Sockets en Java (TCP) Se utilizan dos clases de socket (una para el cliente y otra para socket servidor). Para el cliente: Socket(InetAddress dir, int puerto) Crea un socket stream para el cliente conectado con la dirección y puerto indicados. Existen otros constructores con diferentes argumentos. Para el servidor: ServerSocket(int puerto) Crea un socket stream para el servidor. Existen otros constructores con diferentes argumentos. Socket accept() Prepara la conexión y se bloquea a espera de conexiones. Equivale a listen y accept de BSD Sockets. Devuelve un Socket.
Sockets en Java (TCP) La lectura y la escritura sobre sockets TCP se realiza por medio de objetos derivados de las clases de Stream (en concreto subclases de InputStream y OutputStream). InputStream getInputStream() Obtiene el stream de lectura. OutputStream getOutputStream() Obtiene el stream de escritura.
Los objetos devueltos son transformados a la subclase apropiada para manejarlo (por ejemplo DataInputStream).
Sockets en Java Para la confección de diferentes protocolos o variantes de los mismos Java proporciona un interfaz denominado SocketImplFactory. SocketImpl createSocketImpl() Crea una instancia de la superclase de sockets.
SocketImpl es la superclase de todos las implementaciones de sockets. Un objeto de esta clase es usado como argumento para la creación de sockets.
Página anterior | Volver al principio del trabajo | Página siguiente |