Documente Academic
Documente Profesional
Documente Cultură
§ API de programación
q Sockets en C
q Sockets en Java
§ Abstracción que:
q Representa un extremo de una comunicación bidireccional con una dirección
asociada
q Ofrece interfaz de acceso a la capa de transporte del protocolo TCP/IP
} Protocolo TCP y UDP
F. García Carballeira, Sistemas Distribuidos
3
Sockets: introducción
§ Dominios de comunicación
q AF_UNIX
q AF_INET
q AF_INET6
§ Tipos de sockets
q Stream (SOCK_STREAM)
q Datragrama (SOCK_DGRAM)
§ Direcciones de sockets
§ Ejemplos de dominios:
q AF_UNIX: comunicación dentro de una máquina
q AF_INET: comunicación usando protocolos TCP/IP (IPv4)
q AF_INET6: comunicación usando protocolos TCP/IP (IPv6)
§ Stream (SOCK_STREAM)
q Protocolo TCP
§ Datagrama (SOCK_DGRAM)
q Protocolo UDP
§ Raw (SOCK_RAW)
q Sockets sin protocolo de
transporte (IP)
§ Protocolo TCP
§ Flujo de datos bidireccional
§ Orientado a conexión
q Debe establecerse una conexión extremo-a-extremo antes del
envío y recepción de datos
q Flujo de bytes (no preserva el límite entre mensajes)
q Proporciona fiabilidad
} Paquetes ordenados por secuencia, sin duplicación de
paquetes, libre de errores, notifica errores
§ Ejemplos:
q HTTP, Telnet, FTP, SMTP
§ Protocolo UDP
§ Flujo de datos bidireccional
§ No orientado a conexión
q No se establece/mantiene una conexión entre los procesos que
comunican
q Un datagrama es una entidad autocontenida
} Se preservan los límites entre mensajes
q Longitud máxima de un datagrama (datos y cabeceras) es 64
KB
} Cabecera IP+cabecera UDP = 28 bytes
q Mantiene separación entre paquetes
q No proporcionan fiabilidad
} Paquetes desordenados, duplicados, pérdidas
§ Ejemplos:
q DNS
F. García Carballeira, Sistemas Distribuidos
9
Sockets: stream y datagramas
socket socket
API runtime Process A Process B API runtime
support support
socket socket
API runtime Process A Process B API runtime
support support
Datos
Datos
Puerto Origen
Puerto Destino
Cabecera
TCP Datos
Datos
Puerto Origen
Puerto Destino
Cabecera
TCP Datos
Protocolo =TCP
IP Origen
IP Destino
Cabecera Cabecera
IP TCP Datos
Datos
Puerto Origen
Puerto Destino
Cabecera
TCP Datos
Protocolo =TCP
IP Origen
IP Destino
Cabecera Cabecera
IP TCP Datos
Tipo de trama = IP
Dirección Eth. Origen
Dirección Eth. Destino
Cabecera Cabecera Cabecera Cola
Ethernet IP TCP Datos Ethernet
#include <netinet/in.h>
struct in_addr {
in_addr_t s_addr; /*entero sin signo de 32 bits*/
};
struct sockaddr_un
#include <sys/un.h>
struct sockaddr_un { family
short sun_family; Pathname
char sun_path[108]; (up to 108
}; bytes)
donde:
name referencia al buffer donde se almacena el nombre
namelen longitud del buffer
int main ()
{
char maquina[256];
int err;
if (err != -1)
printf("Ejecuto en la maquina %s\n", maquina);
exit(0);
}
ã The McGraw-Hill
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);
}
exit(0);
}
ã The McGraw-Hill
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));
return 0;
}
if (argc != 2) {
printf("USO: %s Direccion-IP\n", argv[0]);
return (1);
}
err = inet_aton(argv[1], &addr);
if (err == 0) {
printf("Direccion IP en formato a.b.c.d\n");
return (2);
}
if (hp == NULL) {
printf("Error en ....\n");
return (3);
}
for (p = hp->h_addr_list; *p!=0; p++){
memcpy(&in.s_addr, *p, sizeof(in.s_addr));
printf("%s es \t%s \n", inet_ntoa(in), hp->h_name);
for (q=hp->h_aliases; *q != 0; q++)
printf("%s\n", *q);
}
return(0);
}
§ Little-endian
§ Big Endian
MSB LSB
0 0 0 1
Direcciones: n n+1 n+2 n+3
Dirección de crecimiento
§ Little Endian
MSB LSB
1 0 0 0
Direcciones: n+3 n+2 n+1 n
Dirección de crecimiento
Representación en el computador A
…10010111…0110010…
§ Desempaquetamiento de datos (unmarshalling)
q Conversión de los datos a su representación interna
ã The McGraw-Hill
socket()
Proceso cliente
bind()
socket() listen()
Conexión
connect() accept()
Petición
write() read()
Respuesta
read() write()
close() close()
socket()
Proceso cliente
bind()
socket()
Petición
sendto() recvfrom()
Respuesta
recvfrom() sendto()
close() close()
§ Crear un socket:
#include <sys/socket.h>
int socket(int dominio, int tipo, int protocolo)
Argumentos:
dominio AF_UNIX, AF_INET
tipo SOCK_STREAM, SOCK_DGRAM
protocolo dependiente del dominio y tipo
} 0 en el caso general
} Especificados en /etc/protocols
devuelve:
si éxito, un descriptor de socket
si error, -1
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
int main()
{
/* VARIABLES DEL PROGRAMA */
int sockfd;
return(0);
}
Argumentos:
sd descriptor devuelto por socket
addr dirección a asignar
addrlen longitud de la dirección/tamaño de la estructura sockaddr
Argumentos:
sd: descriptor devuelto por socket
backlog: número máximo de peticiones que se encolarán.
Máximo definido en SOMAXCONN (<sys/socket.h>).
#include <sys/socket.h>
Argumentos:
sd descriptor devuelto por socket
dir dirección del socket del cliente
len 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 en dir
Argumentos:
sd descriptor devuelto por socket
dir dirección del socket remoto
len longitud de la dirección del socket remoto
socket()
Proceso cliente
bind()
socket() listen()
Conexión
connect() accept()
Petición
write() read()
Respuesta
read() write()
close() close()
TCP (clientes)
socket()
Proceso cliente
bind()
socket() listen()
Respuesta
#include <netdb.h>
read() write()
close() close()
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
bind()
listen()
socket()
Respuesta
close() close()
socket()
Proceso cliente
bind()
Conexión
Respuesta
read()
read() write()
#include <sys/socket.h>
int main() {
int sd, newsd;
socklen_t size;
struct sockaddr_in server_addr, client_addr;
/* bind */
if (bind(sd,(struct sockaddr *)&server_addr,
sizeof(server_addr)) <0) {
printf("Error en el bind\n"); Proceso servidor
bind()
} socket() listen()
Conexión
connect() accept()
Petición
write() read()
Respuesta
read() write()
close() close()
bind()
} socket() listen()
Conexión
connect() accept()
close(sd);
} /* fin main */ write()
Petición
read()
Respuesta
read() write()
close() close()
#include <unistd.h>
int read(int sd, char *mem, int long);
if (r < 0)
return (-1); /* fallo */
else
return(0); /* se ha enviado longitud */
}
if (r < 0)
return (-1); /* fallo */
else
return(0);/* se ha recibido longitud bytes */
}
§ No hay conexión
§ Para usar un socket para transferir datos basta con:
q Crearlo (socket)
q Asignarle una dirección (bind)
} Si no se le asigna dirección, lo hará el sistema de manera transparente
§ Envío:
#include <sys/types.h>
#include <sys/socket.h>
int sendto(int sd, const void *buffer, size_t len, int flags,
const struct sockaddr *dir, socklent_t addrlen)
§ Recepción:
#include <sys/types.h>
#include <sys/socket.h>
int recvfrom(int sd, void *buffer, size_t len,
int flags, struct sockaddr *dir, socklent_t addrlen):
} Devuelve –1 si error
Servidor cliente
(host-A, 22) (host-B, 1500)
Servidor cliente
(host-A, 22) (host-B, 1500)
Servidor cliente
(host-A, 22) (host-B, 1500)
connect()
accept() (tcp, host-A, 22, -, -) (tcp, host-B, 1500, -, -)
Servidor cliente
(host-A, 22) (host-B, 1500)
connect()
accept() (tcp, host-A, 22, -, -) (tcp, host-B, 1500, -, -)
Servidor cliente
(host-A, 22) (host-B, 1500)
Conexión
(tcp, host-A, 22, host-B, 1500)
Servidor cliente
(host-A, 22) (host-B, 1500)
Conexión
(tcp, host-A, 22, host-B, 1500)
Servidor cliente
(host-A, 22) (host-B, 1500)
Conexión
Servidor cliente
(host-A, 22) (host-B, 1500)
Conexión
Servidor cliente
(host-A, 22) (host-B, 1500)
Conexión
Servidor cliente
(host-A, 22) (host-B, 1500)
Conexión
int option = 1;
rc = setsockopt(s, IPPROTO_TCP,
TCP_NODELAY,
&option,
sizeof(option));
§ DatagramPacket:
q Implementa un objeto que permite enviar o recibir paquetes
q Constructor: DatagramPacket
q Métodos: getAddress, getPort, ...
§ DatagramSocket:
q Implementa un socket que se puede utilizar para enviar o recibir
datagramas.
q Constructor: DatagramSocket
q Métodos: send, receive, close, setSoTimetout, getSoTimeout,...
Servidor
Cliente ServerSocket(puerto);
OutputStream InputStream
InputStream OutputStream
close() close()
IP UDP TCP
¿Orientado a conexión? No No Si
¿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
petición
Cliente servidor
respuesta
Máquina A Máquina B
sumar(5,2)
cliente servidor
5+2
RED
Proceso servidor
socket()
Proceso cliente
bind()
socket() listen()
Conexión
connect() accept()
Petición
write() read()
Respuesta
read() write()
close() close()
bind()
socket() listen()
Conexión
connect() accept()
Respuesta
#include <unistd.h> read() write()
close() close()
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(int argc, char *argv[]){
struct sockaddr_in server_addr, client_addr;
int sd, sc;
int val;
char op;
int32_t num[2], res;
if ((sd = socket(AF_INET, SOCK_STREAM, 0))<0){
printf ("SERVER: Error en el socket");
return (0);
}
val = 1;
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(int));
bind()
socket() listen()
Conexión
connect() accept()
Petición
write() read()
Respuesta
read() write()
close() close()
bind()
socket() listen()
Conexión
connect() accept()
Respuesta
printf("esperando conexion\n"); read() write()
close() close()
bind()
socket() listen()
Conexión
connect() accept()
Respuesta
#include <netdb.h> read() write()
close() close()
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
bind()
socket() listen()
Conexión
connect() accept()
Petición
write() read()
Respuesta
read() write()
close() close()
// se establece la conexión
connect(sd, (struct sockaddr *) &server_addr,
sizeof(server_addr));
bind()
socket() listen()
Conexión
connect() accept()
Petición
write() read()
Respuesta
read() write()
num[1]=2;
op = 0; // suma
close (sd);
return(0);
} /* fin main */
Máquina A Máquina B
sumar(5,2)
cliente servidor
5+2
RED
Proceso servidor
socket()
Proceso cliente
bind()
socket()
Petición
sendto() recvfrom()
Respuesta
recvfrom() sendto()
close() close()
bind()
socket()
#include <stdio.h>
Petición recvfrom()
sendto()
#include <strings.h> Respuesta
recvfrom() sendto()
#include <sys/socket.h>
#include <arpa/inet.h>
int main(void) {
int32_t num[3];
int s, res, clilen;
struct sockaddr_in server_addr, client_addr;
while (1){
recvfrom(s, (char *) num, 3* sizeof(int32_t), 0,
(struct sockaddr *)&client_addr, &clilen);
if (num[0]== 0)
res = num[1] + num[2];
else
res = num[1] - num[2];
bind()
socket()
#include <stdio.h>
Petición recvfrom()
sendto()
#include <unistd.h> Respuesta
recvfrom() sendto()
#include <netdb.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
if (argc != 2){
printf("Uso: cliente <direccion_servidor> \n");
return(0);
}
bind()
socket()
Respuesta
recvfrom()
recvfrom() sendto()
bind()
socket()
sizeof(client_addr));
Respuesta
recvfrom() sendto()
close() close()
num[0] = 0; // sumar
num[1] = 5;
num[1] = 2;
Máquina A Máquina B
sumar(5,2)
cliente servidor
5+2
RED
ostream.writeInt(res);
ostream.flush();
sc.close();
}
catch(Exception e) {
System.err.println("excepcion " + e.toString() );
e.printStackTrace() ;
}
}
}
}
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
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() ;
}
}
}
petición
servidor
Cliente
Crea un proceso
hijo
respuesta
Proceso
hijo
socket()
Proceso cliente
bind()
socket() listen()
Abrir conexión
accept()
connect()
Crear proceso
hijo
Petición
write() read()
Respuesta
read() write()
close() close()
socket()
Proceso cliente
bind()
socket()
Petición
sendto() recvfrom()
Crear proceso
Respuesta hijo
recvfrom()
sendto()
close() close()
for(;;) {
sd = accept(s, (struct sockaddr *)&cliente, &len);
signal(SIGCHLD, SIG_IGN);
petcición
servidor
Cliente
Crea thread
de servicio
respuesta
Thread de
servicio
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);
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);
while (true){
try {
Socket cliente = serverAddr.accept();
new TratarPeticion(cliente).start();
}
catch(Exception e) {
System.err.println("excepcion " + e.toString() );
e.printStackTrace() ;
}
}
}
}
TratarPeticion(Socket s) {
sc = s;
}