MECANISMO DE COMUNICACIÓN
REMOTA
SOCKET
COMUNICACIÓN REMOTA: FORMATO DE RED © UPM 2016
Hay arquitecturas de computador que representan los números enteros de
manera distinta: Little-endian vs. Big-endian
Para transmitir enteros, hay que convertirlos a/de formato independiente
htonl()
htons()
Convierten enteros largos y cortos de formato del host a formato de red
ntohl()
ntohs()
Convierten enteros largos y cortos de formato del red a formato del host
Por ejemplo, el campo sockaddr_in.sin_port (número de puerto)
debe estar en formato red
La comunicación de datos de otros tipos básicos (Ej. coma flotante) o
estructuras exige otros métodos de conversión que no son estándar
Por simplicidad, muchos protocolos usan texto como formato
independiente y transmiten otros datos sin formato específico en binario
(8 bits)
45
MECANISMO: SOCKET © UPM 2016
Mecanismo del SO para comunicación Tipo
dentro del mismo dominio Stream (SOCK_STREAM)
Con nombre (dirección) – Orientado a flujo de datos
Bidireccional – CON conexión
Con buffering – Fiable: asegura entrega y orden
– [≈ Conversación telefónica]
Bloqueante o no
Datagrama (SOCK_DGRAM)
int socket (int dominio,
– Orientado a mensajes
int tipo, int protocolo);
– SIN conexión
Crea un socket (sin dirección) del
dominio, tipo y protocolo dados y – No fiable: pérdida y desorden
devuelve descriptor asociado sd – [≈ Correspondencia postal]
Dominio == familia de direcciones Protocolo
AF_UNIX: intra-máquina Mensajes y reglas de intercambio
(Dir. = nombre de fichero) entre comunicantes
AF_INET: entre máquinas En AF_INET (== Internet) existen
(Dir. = dirección IP + nº de puerto) dos protocolos de transporte:
Mismos servicios para todo – IPPROTO_TCP, para stream
dominio, pero diferente tipo de – IPPROTO_UDP, para datagrama
direcciones 46
DIRECCIONES DE IPV4 © UPM 2016
Las direcciones dependen del dominio, Una transmisión IP está
pero los servicios no (uso de cast) caracterizada por cinco parámetros:
struct sockaddr Protocolo (UDP o TCP)
estructura genérica de dirección
Dirección host + puerto origen
struct sockaddr_in
estructura específica AF_INET Dirección host + puerto destino
– Debe iniciarse a 0 (bzero) Cada socket debe estar asociado a:
– sin_family: AF_INET una dirección local única
– sin_addr: dirección del host y una dirección remota sii:
(32 bits) (4 octetos [0..255]) – está conectado
– sin_port: número de puerto – o para cada mensaje
(16 bits) (1024 reservados)
Para los usuarios son texto
"138.100.8.100" ó "laurel.datsi.fi.upm.es"
int inet_pton(int af, const char *src, void *dst);
Conversión a binario (formato red IPv4 o IPv6) desde decimal-punto
struct hostent *gethostbyname (char *str);
Conversión a binario (formato red) desde dominio-punto
47
SOCKET: SERVICIOS © UPM 2016
int socket (int dominio, int tipo, int protocolo);
Crea un socket (sin dirección) del dominio, tipo y protocolo dados
int bind (int sd, struct sockaddr *dir, int tam);
Asociar a una dirección local
int connect (int sd, struct sockaddr *dir, int tam);
Asociar a una dirección remota (cliente)
int listen (int sd, int baklog);
Prepara para aceptar conexiones (servidor)
int accept (int sd, struct sockaddr *dir, int *tam);
Aceptación de una conexión (servidor)
int send (int sd, char *mem, int tam, int flags);
int recv (int sd, char *mem, int tam, int flags);
Transmisión para conectados (también read y write)
int sendto (int sd, char *mem, int tam, int flags,
struct sockaddr *dir, int len);
int recvfrom (int sd, char *mem, int tam, int flags,
struct sockaddr *dir, int *len);
Transmisión para NO conectados
48
DGRAM CORRESPONDENCIA POSTAL © UPM 2016
Cliente Servidor SIN estado
(Inicia la conversación) (Recibe mensajes y los atiende)
socket socket
Adquirir buzón UDP Adquirir buzón UDP
bind bind
Asignarle una dirección libre Asignarle dirección bien conocida
sendto
Enviar carta con remite: ¿Hola? recvfrom
Recoger carta
Tomar dirección del remitente
sendto
recvfrom Enviar al remitente: ¿Dígame?
Recoger respuesta
close
Eliminar buzón close
Eventualmente, eliminar buzón
49
CLIENTE-SERVIDOR UDP
© UPM 2016
Máquina Cliente A Máquina Servidor B
Demonio
puertos UDP
puertos UDP
Proceso
Servidor
Cliente
SIN estado
cd=socket(UDP) sd=socket(UDP)
cd sd
bind(cd,0)
bind(sd,7)
1025 7
sendto(cd,B:7)
recvfrom(sd,caddr)
sendto(sd,caddr)
recvfrom(cd,B:7)
close(cd)
NO fiable: pérdidas,
desorden, duplicados
50
CLIENTE UDP
© UPM 2016
int main(int argc, char * argv[])
{
int cd, size ;
struct hostent * hp;
struct sockaddr_in s_ain, c_ain;
unsigned char byte;
hp = gethostbyname(argv[1]); /* por ejemplo, otilio.fi.upm.es */
bzero((char *)&s_ain, sizeof(s_ain));
s_ain.sin_family = AF_INET;
memcpy (&(s_ain.sin_addr), hp->h_addr, hp->h_length);
s_ain.sin_port = htons(7); /* echo port */
cd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bzero((char *)&c_ain, sizeof(c_ain));
c_ain.sin_family = AF_INET;
O se hace el
bind(cd, (struct sockaddr *)&c_ain, sizeof(s_ain));
size = sizeof(c_ain); bind explícito o el
while(read( 0, &byte, 1) == 1) { sendto lo hará
sendto(cd, &byte, 1, 0, (struct sockaddr *)&s_ain, size); implícitamente
recvfrom(cd, &byte, 1, 0, (struct sockaddr *)&s_ain, &size);
write(1, &byte, 1);
}
close(cd);
return 0;
}
Si se pierde un byte
se “cuelga” el cliente
51
SERVIDOR UDP © UPM 2016
int main(void)
{
int sd, size;
unsigned char byte;
struct sockaddr_in s_ain, c_ain;
sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bzero((char *)&s_ain, sizeof(s_ain));
s_ain.sin_family = AF_INET;
s_ain.sin_addr.s_addr = INADDR_ANY; /*Cualquier origen*/
s_ain.sin_port = htons(7); /* echo server */
bind(sd, (struct sockaddr *)&s_ain, sizeof(s_ain));
size = sizeof(c_ain);
while (1) {
recvfrom(sd, &byte, 1, 0, (struct sockaddr *)&c_ain, &size);
sendto(sd, &byte, 1, 0, (struct sockaddr *)&c_ain, size);
}
}
52
STREAM ≈ CONVERSACIÓN TELEFÓNICA © UPM 2016
Cliente Centralita Servidor
(Inicia la conversación) (Recibe llamada y redirige)
socket socket
Adquirir teléfono Adquirir centralita
bind bind
Contratar línea (nº de teléfono) Contratar línea (nº de teléfono)
connect listen
Descolgar Dimensionar centralita
Marcar accept
Esperar establecimiento llamada Esperar establecimiento llamada
Redirigir a teléfono de servicio
Servidor dedicado
(Atiende la conversación)
send & recv send & recv
Saludo: ¿Hola? Saludo: ¿Qué desea?
send & recv send & recv
Diálogo: Quisiera Diálogo: ¡Cómo no
¡Gracias! Aquí tiene
close close
Colgar Colgar 53
CLIENTE-SERVIDOR TCP (SERVIDOR CONCURRENTE)
© UPM 2016
Máquina Cliente A Máquina Servidora B
puertos TCP
puertos TCP
Proceso Demonio
Cliente Servidor
sd=socket(TCP)
cd=socket(TCP) sd
bind(sd,7)
bind(cd,1025) cd listen(sd,5)
connect(cd,B:7) cd=accept(sd)
cd
close(cd)
1025 7 fork()
Servidor
send(cd) dedicado
sd close(sd)
Conexión: recv(cd)
TCP:A:1025:B:7
send(cd)
recv(cd)
cd
Fiable: asegura close(cd)
close(cd)
entrega y orden
54
CLIENTE TCP
© UPM 2016
int main(int argc, char * argv[])
{
int cd;
struct hostent * hp;
struct sockaddr_in s_ain;
unsigned char byte;
hp = gethostbyname(argv[1]);
bzero((char *)&s_ain, sizeof(s_ain));
s_ain.sin_family = AF_INET;
memcpy (&(s_ain.sin_addr), hp->h_addr, hp->h_length); /* IP */
s_ain.sin_port = htons(7); /* echo port */
cd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
connect(cd, (struct sockaddr *)&s_ain, sizeof(s_ain));
while(read( 0, &byte, 1) == 1) {
send(cd, &byte, 1, 0); /* Bloqueante */
recv(cd, &byte, 1, 0); /* Bloqueante */
write(1, &byte, 1);
}
close(cd);
return 0;
}
55
SERVIDOR TCP (I)
© UPM 2016
int main(void)
{
int sd, cd, size;
unsigned char byte;
struct sockaddr_in s_ain, c_ain;
sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bzero((char *)&s_ain, sizeof(s_ain));
s_ain.sin_family = AF_INET;
s_ain.sin_addr.s_addr = INADDR_ANY; /*Cualquier origen*/
s_ain.sin_port = htons(7); /* echo port */
bind(sd, (struct sockaddr *)&s_ain, sizeof(s_ain));
listen(sd, 5); /* 5 = tamaño cola */
/* continúa... */
56
SERVIDOR TCP (II)
© UPM 2016
while(1) {
size = sizeof(c_ain);
cd = accept(sd, (struct sockaddr *)&c_ain, &size);
switch(fork()) {
case -1:
perror("echo server");
return 1;
case 0:
close(sd);
while(recv(cd, &byte, 1, 0) == 1) /*Bloqueante*/
send(cd, &byte, 1, 0); /*Bloqueante*/
close(cd);
return 0;
default:
close(cd);
} /* switch */
} /* while */
} /* main */
57