• No se han encontrado resultados

Tema 5 Comunicación con sockets

N/A
N/A
Protected

Academic year: 2021

Share "Tema 5 Comunicación con sockets"

Copied!
122
0
0

Texto completo

(1)

Tema 5

Comunicación con sockets

Grupo ARCOS

(2)

Contenido

Conceptos básicos sobre

sockets

Modelo de comunicación

Sockets

Datagrama

Stream

Stream

API de programación

Sockets en

C

Sockets en

Java

(3)

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

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

(4)

Sockets: introducción

RMI and RPC

Sockets

Aplicaciones/servicios

Aplanamiento (marshalling), representación externa

de datos

Protocolo de transporte

(5)

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

(6)

Sockets UNIX

Dominios

de comunicación

AF_UNIX

AF_INET

Tipos

de sockets

Stream (SOCK_STREAM)

Datragrama (SOCK_DGRAM)

Direcciones de sockets

(7)

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

(8)

Tipos de sockets

Stream

(

SOCK_STREAM

)

Protocolo TCP

Datagrama

(

SOCK_DGRAM

)

Protocolo UDP

Raw

(

SOCK_RAW

)

Sockets sin protocolo de

transporte

(9)

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

Proporcionan

fiabilidad

Paquetes ordenados por secuencia, sin duplicación de

paquetes, libre de errores

Ejemplos:

(10)

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

)

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:

(11)

Sockets: stream y datagramas

Process A

socket

API runtime support

Process B

API

socket

runtime support

transport layer software

transport layer software

a datagram

a logical connection created and maintained

connectionless datagram socket

a logical connection created and maintained

by the runtime support of the datagram

socket API

Process A

socket

API runtime support

Process B

API

socket

runtime support

transport layer software

transport layer software

connection-oriented datagram socket

(12)

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

(13)

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

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

)

(14)

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

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

(15)

Protocolo

TCP, UDP

Dirección IP local (origen)

Puerto local (origen)

Dirección IP remota (destino)

Información asociada a una

comunicación

Dirección IP remota (destino)

Puerto remoto (destino)

(16)

Encapsulación de un paquete TCP

(17)

Encapsulación de un paquete TCP

Datos

Datos

Cabecera

TCP

Puerto Origen

Puerto Destino

(18)

Encapsulación de un paquete TCP

Datos

Datos

Puerto Origen

Puerto Destino

Protocolo =TCP

IP Origen

Cabecera

TCP

Datos

Cabecera

TCP

Cabecera

IP

IP Origen

IP Destino

(19)

Encapsulación de un paquete TCP

Datos

Datos

Puerto Origen

Puerto Destino

Protocolo =TCP

IP Origen

Cabecera

TCP

Datos

Cabecera

TCP

Cabecera

IP

Cabecera

Ethernet

Cola

Ethernet

Tipo de trama = IP

Dirección Eth. Origen

Dirección Eth. Destino

Datos

Cabecera

TCP

Cabecera

IP

IP Origen

IP Destino

(20)

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

;

typedef uint32_t

in_addr_t

;

struct in_addr

{

in_addr_t s_addr;

};

(21)

Direcciones de sockets en AF_INET

Estructura

struct sockaddr_in

Debe iniciarse a 0

La estructura tiene

tres campos

importantes:

sin_family:

dominio (AF_INET)

sin_port:

puerto

sin_addr:

dirección del host

family

2-byte port

4-byte

struct sockaddr_in

#include <netinet/in.h>

struct sockaddr_in

{

short

sin_family;

u_short

sin_port;

struct in_addr

sin_addr;

char

sin_zero[8];

};

4-byte

Net ID, host ID

(22)

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

{

family

Pathname

(up to 108

struct sockaddr_un

struct sockaddr_un

{

short

sun_family;

char

sun_path[108];

};

(up to 108

bytes)

(23)

Servicios sobre direcciones

Obtener el

nombre de un host

Transformar direcciones

Obtener la

dirección de un host

Representación de datos

Interna

Interna

Externa

(24)

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:

donde:

name

referencia al buffer donde se almacena el

nombre

(25)

Ejemplo I: obtener nombre host

#include <unistd.h>

void

main

()

{

char maquina[256];

int err;

err =

gethostname

(maquina, 256);

err =

gethostname

(maquina, 256);

printf

(“Ejecuto en la maquina %s\n”, maquina);

exit(0);

}

(26)

Transformación de direcciones

(27)

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,

(28)

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

);

}

(29)

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

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

(30)

Estructura hostent

(31)

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));

}

(32)

#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;

Ejemplo IV:

obtener la dirección de host en decimal-punto

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);

(33)

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++){

Ejemplo IV:

obtener la dirección de host en decimal-punto

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);

}

(34)

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

(35)

Big Endian

1

Ejemplo: Representación del 1

0

0

0

n

n+1 n+2

n+3

Direcciones:

LSB

MSB

Little Endian

0

1

0

0

MSB

LSB

Dirección de crecimiento

n

n+1 n+2

n+3

Direcciones:

(36)

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

-1.5

“Esto es una cadena”

1.2

7.3

Representación

Desempaquetamiento de datos

(unmarshalling)

Conversión de los datos a su

representación interna

…10010111…0110010…

-1.5

“Esto es una cadena”

1.2

7.3

Representación

en el

computador A

(37)

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

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)

(38)

Funciones de transformación

(39)

Modelos de comunicación

Sockets

stream

(SOCK_STREAM)

Orientado a conexión

TCP

Sockets

datagrama

(SOCK_DGRAM)

Sockets

datagrama

(SOCK_DGRAM)

No orientado a conexión

(40)

Modelo de comunicación con sockets

stream

Proceso cliente

Proceso servidor

socket()

socket()

bind()

listen()

Conexión

accept()

read()

close()

connect()

read()

close()

Petición

write()

Respuesta

write()

Conexión

(41)

Modelo de comunicación con sockets

datagrama

Proceso cliente

Proceso servidor

socket()

socket()

bind()

recvfrom()

close()

close()

Petición

sendto()

Respuesta

recvfrom()

sendto()

(42)

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)

Solicitud de conexión (connect)

Obtener la dirección de un socket

Transferencia de datos

Streams

Datagramas

(43)

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

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

(44)

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 */

/* 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 */

}

(45)

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

descriptor devuelto por socket

dir

dirección a asignar

long

longitud de la dirección/tamaño de la estructura sockaddr

devuelve

–1

si

error

y

0

si se ejecutó con

éxito

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

(46)

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

descriptor devuelto por socket

dir

dirección del socket remoto

(47)

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>

#include <sys/socket.h>

int

listen(

int sd, int baklog)

Argumentos:

sd:

descriptor devuelto por socket

backlog:

número máximo de peticiones que se

encolarán (

algunos manuales recomiendan 5

)

(48)

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

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

(49)

Aceptar una conexión (accept)

#include <sys/types.h>

#include <sys/socket.h>

int

accept

(int sd, struct sockaddr *dir, int *long)

Argumentos:

sd

descriptor devuelto por socket

dir

dirección del socket del cliente

dir

dirección del socket del cliente

long

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

(50)

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:

Argumentos:

sd

descriptor devuelto por socket

dir

dirección del socket remoto

long

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

(51)
(52)

Ejemplo VI: Establecimiento de

conexión TCP (clientes)

int

main

()

{

int sockfd;

struct sockaddr_in server;

if ((sockfd=

socket

(AF_INET, SOCK_STREAM, 0))==-1){

printf

(“Error en la creación del socket”);

exit(-1);

}

server.sin_family = AF_INET;

Proceso cliente socket() connect() read() close() Petición write() Respuesta Proceso servidor socket() bind() listen() accept() read() close() write() Conexión

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 */

}

(53)

Ejemplo VI: Establecimiento de

conexión TCP (servidores)

int

main

()

{

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);

}

Proceso servidor socket() bind() listen() accept() read() close() Proceso cliente socket() connect() read() close() Petición write() Respuesta write() Conexión

}

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”);

(54)

Ejemplo VI:

continuación (servidores)

listen

(sd,5)

for (;;) {

if (

newsd

=

accept

(sd,(struct sockaddr *)

&client, sizeof(client)) < 0) {

printf

(“Error en el accept”);

exit(-1);

}

Proceso servidor socket() bind() listen() accept() read() close() Proceso cliente socket() connect() read() close() Petición write() Respuesta write() Conexión

/* transferir datos sobre newsd */

….

/* cerrar newsd */

} /* fin for */

/* cerrar sd */

} /* fin main */

(55)

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,

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

(56)

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.

(57)

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

{

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);

}

(58)

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)

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

(59)

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

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

addrlen

la longitud de la dirección

Es importante comprobar siempre el valor que devuelven

estas llamadas:

pueden

no

transferirse todos los datos.

(60)

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

(61)

Conexión con TCP

Servidor

(host-A, 22)

(tcp, host-A, 22, -, -)

cliente

(host-B, 1500)

(tcp, host-B, 1500, -, -)

(62)

Conexión con TCP

Servidor

(host-A, 22)

(tcp, host-A, 22, -, -)

cliente

(host-B, 1500)

(tcp, host-B, 1500, -, -)

accept()

(63)

Conexión con TCP

Servidor

(host-A, 22)

(tcp, host-A, 22, -, -)

cliente

(host-B, 1500)

(tcp, host-B, 1500, -, -)

connect()

accept()

(64)

Conexión con TCP

Servidor

(host-A, 22)

(tcp, host-A, 22, -, -)

cliente

(host-B, 1500)

(tcp, host-B, 1500, -, -)

connect()

Nuevo descriptor de socket

accept()

Nuevo descriptor de socket

fork()

(65)

Conexión con TCP

Servidor

(host-A, 22)

(tcp, host-A, 22, -, -)

cliente

(host-B, 1500)

(tcp, host-B, 1500, host-A, 22)

Conexión

(tcp, host-A, 22, host-B, 1500)

(66)

Conexión con TCP

Servidor

(host-A, 22)

(tcp, host-A, 22, -, -)

cliente

(host-B, 1500)

(tcp, host-B, 1500, host-A, 22)

accept()

Conexión

(tcp, host-A, 22, host-B, 1500)

(67)

Conexión con TCP

Servidor

(host-A, 22)

(tcp, host-A, 22, -, -)

cliente

(host-B, 1500)

(tcp, host-B, 1500, host-A, 22)

accept()

Conexión

cliente

(host-C, 4000)

(tcp, host-C, 4000, -, -)

(tcp, host-A, 22, host-B, 1500)

(68)

Conexión con TCP

Servidor

(host-A, 22)

(tcp, host-A, 22, -, -)

cliente

(host-B, 1500)

(tcp, host-B, 1500, host-A, 22)

accept()

connect()

Conexión

cliente

(host-C, 4000)

(tcp, host-C, 4000, -, -)

(tcp, host-A, 22, host-B, 1500)

(69)

Conexión con TCP

Servidor

(host-A, 22)

(tcp, host-A, 22, -, -)

cliente

(host-B, 1500)

(tcp, host-B, 1500, host-A, 22)

accept()

Conexión

cliente

(host-C, 4000)

(tcp, host-C, 4000, -, -)

(tcp, host-A, 22, host-B, 1500)

Nuevo descriptor de socket

fork()

(70)

Conexión con TCP

Servidor

(host-A, 22)

(tcp, host-A, 22, -, -)

cliente

(host-B, 1500)

(tcp, host-B, 1500, host-A, 22)

Conexión

cliente

(host-C, 4000)

(tcp, host-C, 4000, host-A, 22)

(tcp, host-A, 22, host-B, 1500)

(tcp, host-A, 22, host-C, 4000)

Conexión

(71)

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

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)

(72)

¿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

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));

(73)

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));

(74)

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,

(75)

Sockets de Java

El paquete

java.net

de Java permite crear sockets

TCP/IP

Clases para sockets datagrama:

DatagramSocket

DatagramSocket

DatagramPacket

Clases para sockets stream:

ServerSocket

Socket

(76)

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

ket.html

DatagramSocket

:

Implementa un socket que se puede utilizar para enviar o recibir

datagramas.

Constructor:

DatagramSocket

Métodos:

send, receive, close, setSoTimetout, getSoTimeout,...

(77)

Sockets datagrama

Vector de bytes

Dirección del

receptor

Proceso emisor

Vector de bytes

Proceso receptor

Objeto DatagramPacket

Objeto DatagramSocket

send

receive

Referencia a objeto

Objeto DatagramPacket

Objeto DatagramSocket

(78)

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

(79)

Ejemplo XI:

Modelo de comunicación

Cliente

ServerSocket(puerto);

accept();

socket(host, puerto)

Servidor

OutputStream

OutputStream

InputStream

InputStream

close()

close()

(80)

Guía de diseño de aplicaciones

cliente-servidor

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

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

(81)

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

¿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

(82)

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

petición

respuesta

(83)

Ejemplo VIII:

Programar un servidor y cliente en TCP

cliente

sumar(5,2)

5+2

servidor

Máquina A

Máquina B

NÚCLEO

Resultado = 7

NÚCLEO

(84)

Ejemplo VIII: Modelo de comunicación

Proceso cliente

Proceso servidor

socket()

socket()

bind()

listen()

Conexión

accept()

read()

close()

connect()

read()

close()

Petición

write()

Respuesta

write()

Conexión

(85)

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;

Proceso servidor socket() bind() listen() accept() read() close() Proceso cliente socket() connect() read() close() Petición write() Respuesta write() Conexión

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;

(86)

Ejemplo VIII: Servidor TCP

listen

(sd, 5);

size =

sizeof(

client_addr);

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

Proceso servidor socket() bind() listen() accept() read() close() Proceso cliente socket() connect() read() close() Petición write() Respuesta write() Conexión

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);

(87)

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");

Proceso cliente socket() connect() read() close() Petición write() Respuesta Proceso servidor socket() bind() listen() accept() read() close() write() Conexión

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;

(88)

Ejemplo VIII: Cliente TCP

// se establece la conexión

connect

(sd, (struct sockaddr *) &server_addr, sizeof(server_addr));

num[0]=5;

num[1]=2;

write

(sd, (char *) num, 2 *

sizeof

(int)); // envía la petición

Proceso cliente socket() connect() read() close() Petición write() Respuesta Proceso servidor socket() bind() listen() accept() read() close() write() Conexión

read

(sd, &res,

sizeof

(int));

// recibe la respuesta

printf

("Resultado es %d \n", res);

close

(sd);

exit

(0);

(89)

Ejemplo IX:

Programar un servidor y cliente en UDP

cliente

sumar(5,2)

5+2

servidor

Máquina A

Máquina B

NÚCLEO

Resultado = 7

NÚCLEO

(90)

Ejemplo IX:

Modelo de comunicación

Proceso cliente

Proceso servidor

socket()

socket()

bind()

recvfrom()

close()

close()

Petición

sendto()

Respuesta

recvfrom()

sendto()

(91)

Ejemplo IX:

Servidor UDP

#include <sys/types.h>

#include <sys/socket.h>

void

main

(void)

{

int num[2];

int s, res, clilen;

struct sockaddr_in server_addr, client_addr;

Proceso cliente Proceso servidor socket() socket() bind() recvfrom() close() close() Petición sendto() Respuesta recvfrom() sendto()

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);

(92)

Ejemplo IX:

Servidor UDP

clilen =

sizeof

(client_addr);

while

(1)

{

recvfrom

(s, (char *) num, 2*

sizeof

(int), 0,

(struct sockaddr *)&client_addr, &clilen);

Proceso cliente Proceso servidor socket() socket() bind() recvfrom() close() close() Petición sendto() Respuesta recvfrom() sendto()

res = num[0] + num[1];

sendto

(s, (char *)&res,

sizeof

(int), 0,

(struct sockaddr *)&client_addr, clilen);

}

(93)

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;

if (argc != 2){

printf

("Uso: cliente <direccion_servidor> \n");

exit

(0);

Proceso cliente Proceso servidor socket() socket() bind() recvfrom() close() close() Petición sendto() Respuesta recvfrom() sendto()

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;

(94)

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);

bind

(s, (struct sockaddr *)&client_addr,

sizeof

(client_addr));

num[0] = 2;

num[1] = 5;

Proceso cliente Proceso servidor socket() socket() bind() recvfrom() close() close() Petición sendto() Respuesta recvfrom() sendto()

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);

}

(95)

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

(96)

Ejemplo X:

Programar un servidor y cliente

usando sockets datagramas de Java

cliente

sumar(5,2)

5+2

servidor

Máquina A

Máquina B

NÚCLEO

5+2

Resultado = 7

NÚCLEO

RED

(97)

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];

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);

(98)

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;

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

(99)

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);

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() ;

}

}

}

(100)

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;

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 {

(101)

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];

(102)

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() ;

}

}

}

(103)

Ejemplo XI:

Programar un servidor y cliente

usando sockets stream de Java

cliente

sumar(5,2)

5+2

servidor

Máquina A

Máquina B

NÚCLEO

5+2

Resultado = 7

NÚCLEO

RED

(104)

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;

Socket sc = null;

int num[] ; // petición

int res;

try {

serverAddr = new ServerSocket(2500);

}

catch (Exception e){

System.err.println("Error creando socket");

}

(105)

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() ;

}

}

(106)

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];

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];

(107)

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

();

res = istream.

readInt

();

sc.

close

();

System.out.println("La suma es " + res);

}

catch (Exception e){

System.err.println("excepcion " + e.toString() );

e.printStackTrace() ;

}

}

}

(108)

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

respuesta

Crea un proceso

hijo

Proceso

hijo

(109)

Servidores concurrentes con sockets

stream

Proceso cliente

Proceso servidor

socket()

socket()

bind()

listen()

Abrir conexión

accept()

read()

close()

connect()

Abrir conexión

read()

close()

Petición

write()

Respuesta

write()

Crear proceso

hijo

(110)

Modelo de comunicación con sockets

datagrama

Proceso cliente

Proceso servidor

socket()

socket()

bind()

recvfrom()

close()

close()

Petición

sendto()

Respuesta

recvfrom()

sendto()

Crear proceso

hijo

(111)

Tipos de servidores concurrentes

Un

proceso servidor concurrente

puede crear dos

tipos de procesos:

Procesos convencionales

(fork)

(112)

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”);

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 */

}

Referencias

Documento similar

Para poder corroborar la optimización del tiempo medido, se ha desarrollado un cliente exactamente igual que el principal, pero utilizando las funciones de los sockets

del proceso de comunicación con los demás, no sólo como medio de comunicación, sino también como fuente de poder, como necesidad social y como una forma de obtener conocimiento y

Given the evidence of HE 1353−1917 and the similar outflow seen in 3C 326, we propose that a significant [C ii] line excess in luminous AGN, if detected, can be used as an inference

El primer paso en este nivel, es analizar y determinar la plataforma que se adapte mejor a las características del curso que se está desarrollando. Es imprescindible un proceso

El presente estudio ha tenido como objetivo revisar la literatura existente acerca del mecanizado CNC y la consiguiente tecnología CAD/CAM/CAE en la fabricación de sockets protésicos

A partir de la opción “búsqueda en las definiciones” de ambos diccionarios, hemos hecho un listado de todas las entradas en las que aparece la palabra “silencio”; somos

Cuando el cliente realiza una petición, mediante una opción que indica el método a utilizar para solicitar un recurso (identificado por una URI), el servidor envía

(Q FRQWUDVWH ORV FOLHQWHV \ VHUYLGRUHV TXH XVDQ 8'3 VH FDUDFWHUL]DQ SRU QR WHQHU JDUDQWtDV VREUH OD ILDELOLGDG GH OD HQWUHJD &amp;XDQGR XQ FOLHQWH HQYtD