Está en la página 1de 121

Tema 5

Comunicación con sockets


F. García-Carballeira, Mª. Soledad Escolar,
Luis Miguel Sánchez, Fco. Javier García

Sistemas Distribuidos
Grado en Ingeniería Informática
Universidad Carlos III de Madrid
Contenido
 Conceptos básicos sobre sockets
 Modelo de comunicación
 Sockets
 Datagrama
 Stream
 API de programación
 Sockets en C
 Sockets en Java
 Guía de diseño de aplicaciones cliente-servidor

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
2
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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 (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
 Protocolo TCP y UDP

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
3
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Sockets: introducción

Aplicaciones/servicios

RMI and RPC

Sockets

Aplanamiento (marshalling), representación externa


de datos

Protocolo de transporte

UDP y TCP

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
4
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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
 En Java como clase nativa

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
5
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Sockets UNIX
 Dominios de comunicación
 AF_UNIX
 AF_INET
 Tipos de sockets
 Stream (SOCK_STREAM)
 Datragrama (SOCK_DGRAM)
 Direcciones de sockets

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
6
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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
 AF_INET: comunicación usando protocolos TCP/IP

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
7
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Tipos de sockets
 Stream (SOCK_STREAM)
 Protocolo TCP

 Datagrama (SOCK_DGRAM)
 Protocolo UDP

 Raw (SOCK_RAW)
 Sockets sin protocolo de transporte

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
8
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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
 Paquetes ordenados por secuencia, sin duplicación de
paquetes, libre de errores

 Ejemplos:
 HTTP, Telnet, FTP, SMTP

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
9
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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) es 64
KB
 Mantiene separación entre paquetes
 No proporcionan fiabilidad
 Paquetes desordenados, duplicados, pérdidas
 Ejemplos:
 DNS

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
10
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Sockets: stream y datagramas

socket socket
API runtime Process A Process B API runtime
support support

transport layer software transport layer software

connectionless datagram socket


a datagram
a logical connection created and maintained
by the runtime support of the datagram
socket API

socket socket
API runtime Process A Process B API runtime
support support

transport layer software transport layer software

connection-oriented datagram socket

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
11
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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

AF_INET SOCK_RAW IPPROTO_RAW raw

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
12
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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


 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)
 Es necesario la conversión de tipos (casting) en las llamadas

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
13
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Puertos
 Un puerto identifica un destino en un computador
 Los puertos se asocian a procesos,
 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
 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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
14
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Información asociada a una
comunicación
 Protocolo
 TCP, UDP
 Dirección IP local (origen)
 Puerto local (origen)
 Dirección IP remota (destino)
 Puerto remoto (destino)

(Protocolo, IP-local, P-local, IP-remoto, P-remoto)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
15
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Encapsulación de un paquete TCP
Datos

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
16
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Encapsulación de un paquete TCP
Datos
Puerto Origen
Puerto Destino
Cabecera
TCP Datos

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
17
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Encapsulación de un paquete TCP
Datos
Puerto Origen
Puerto Destino
Cabecera
TCP Datos
Protocolo =TCP
IP Origen
IP Destino
Cabecera Cabecera
IP TCP Datos

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
18
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Encapsulación de un paquete TCP
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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
19
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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;


struct in_addr
{
in_addr_t s_addr;
};

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
20
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Direcciones de sockets en AF_INET
 Estructura struct sockaddr_in
 Debe iniciarse a 0
 La estructura tiene tres campos importantes
struct sockaddr_in
 sin_family: dominio (AF_INET) family
 sin_port: puerto
 sin_addr: dirección del host
2-byte port

4-byte
#include <netinet/in.h>
struct sockaddr_in { Net ID, host ID
short sin_family; unused
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
21
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Direcciones de sockets en AF_UNIX
 La estructura struct sockaddr_un describe la dirección de
un socket AF_LOCAL o AF_UNIX

struct sockaddr_un
#include <sys/un.h>
struct sockaddr_un { family
short sun_family; Pathname
char sun_path[108]; (up to 108
}; bytes)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
22
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Servicios sobre direcciones
 Obtener el nombre de un host
 Transformar direcciones
 Obtener la dirección de un host
 Representación de datos
 Interna
 Externa

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
23
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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:
name referencia al buffer donde se almacena el
nombre
namelen longitud del buffer

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
24
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo I: obtener nombre host
#include <unistd.h>

void main ()
{
char maquina[256];
int err;

err = gethostname(maquina, 256);

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

exit(0);
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
25
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Transformación de direcciones

 The McGraw-Hill
F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
26
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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,


struct in_addr *in);

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
27
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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);
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
28
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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

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
type es AF_INET

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
29
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Estructura hostent

 The McGraw-Hill
F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
30
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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));


}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
31
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo IV:
obtener la dirección de host en decimal-punto
#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;

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
32
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo IV:
obtener la dirección de host en decimal-punto

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
33
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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

 Little-endian

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
34
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo: Representación del 1
 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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
35
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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

“Esto es una cadena” 1.2 7.3 -1.5

Representación en el computador A
…10010111…0110010…
 Desempaquetamiento de datos (unmarshalling)
 Conversión de los datos a su representación interna

“Esto es una cadena” 1.2 7.3 -1.5


Representación en el computador B
F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
36
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Funciones de transformación:
network  host
 En computadores que no utilicen Big-endian 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
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)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
37
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Funciones de transformación

 The McGraw-Hill

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
38
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Modelos de comunicación
 Sockets stream (SOCK_STREAM)
 Orientado a conexión
 TCP

 Sockets datagrama (SOCK_DGRAM)


 No orientado a conexión
 UDP

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
39
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Modelo de comunicación con sockets
stream
Proceso servidor

socket()
Proceso cliente
bind()

socket() listen()

Conexión
connect() accept()

Petición
write() read()

Respuesta
read() write()

close() close()

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
40
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Modelo de comunicación con sockets
datagrama
Proceso servidor

socket()
Proceso cliente
bind()

socket()

Petición
sendto() recvfrom()

Respuesta
recvfrom() sendto()

close() close()

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
41
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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)
 Obtener la dirección de un socket
 Transferencia de datos
 Streams
 Datagramas
 Cerrar un socket (close)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
42
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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
 0 elige el más adecuado
 Especificados en /etc/protocols

devuelve:
si éxito, un descriptor de socket
si error, -1

 El socket creado no tiene dirección asignada

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
43
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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 */
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 */
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
44
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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

 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 primera utilización (connect o sendto)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
45
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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

 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
long parámetro valor-resultado

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
46
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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>
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)
antes de ejecutar accept
devuelve –1 si error y 0 si se ejecutó con éxito

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
47
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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
 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
 El nuevo para enviar/recibir datos por la conexión establecida

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
48
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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
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


 -1 en caso de error

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
49
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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:
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
F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
50
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Establecimiento de una conexión en TCP

@Fuente: James F. Kurose, Keith W. Ross Computer Networking: A Top-Down Approach

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
51
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

Ejemplo VI: Establecimiento de Proceso cliente


socket()

bind()

conexión TCP (clientes) socket()

connect()
Conexión
listen()

accept()

int main() write()


Petición
read()

Respuesta
{ read() write()

close() close()
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;
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 */
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
52
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

Ejemplo VI: Establecimiento de Proceso cliente


socket()

bind()

conexión TCP (servidores) socket()

connect()
Conexión
listen()

accept()

int main() { write()


Petición
read()

Respuesta
read() write()

int sd, newsd, size; close()


close()

struct sockaddr_in server, client;

if ((sd=socket(AF_INET, SOCK_STREAM, 0))==-1){


printf(“Error en la creación del socket”);
exit(-1);
}
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”);
exit(-1);
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
53
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

Ejemplo VI: Proceso cliente


socket()

bind()

continuación (servidores) socket()

connect()
Conexión
listen()

accept()

Petición

listen(sd,5) write()

read()
Respuesta
read()

write()

close()

for (;;) { close()

if (newsd=accept (sd,(struct sockaddr *)


&client, sizeof(client)) < 0) {
printf(“Error en el accept”);
exit(-1);
}
/* transferir datos sobre newsd */
….
/* cerrar newsd */
} /* fin for */
/* cerrar sd */
} /* fin main */

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
54
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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, 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

 Pueden no transferirse todos los datos


 Es importante comprobar siempre el valor que devuelven estas
llamadas
F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
55
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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

 Pueden no transferirse todos los datos


 Es importante comprobar siempre el valor que devuelven estas
llamadas

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
56
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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 {
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);
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
57
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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)

 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
addrlen la longitud de la dirección

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
58
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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
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 remoto
addrlen la longitud de la dirección

 Pueden no transferirse todos los datos


 Es importante comprobar siempre el valor que devuelven estas
llamadas

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
59
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Cerrar un socket (close)
 Se usa close para cerrar ambos tipos de sockets (stream y
datagrama)
int close(int sd);

 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

 Devuelve –1 si error

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
60
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Conexión con TCP

Servidor cliente
(host-A, 22) (host-B, 1500)

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
61
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Conexión con TCP

Servidor cliente
(host-A, 22) (host-B, 1500)

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
62
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Conexión con TCP

Servidor cliente
(host-A, 22) (host-B, 1500)

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
63
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Conexión con TCP

Servidor cliente
(host-A, 22) (host-B, 1500)

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

Nuevo descriptor de socket


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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
64
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Conexión con TCP

Servidor cliente
(host-A, 22) (host-B, 1500)

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

Conexión
(tcp, host-A, 22, host-B, 1500)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
65
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Conexión con TCP

Servidor cliente
(host-A, 22) (host-B, 1500)

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

Conexión
(tcp, host-A, 22, host-B, 1500)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
66
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Conexión con TCP

Servidor cliente
(host-A, 22) (host-B, 1500)

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

Conexión

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


cliente
(host-C, 4000)

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
67
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Conexión con TCP

Servidor cliente
(host-A, 22) (host-B, 1500)

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


connect()

Conexión

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


cliente
(host-C, 4000)

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
68
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Conexión con TCP

Servidor cliente
(host-A, 22) (host-B, 1500)

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

Conexión

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


cliente
(host-C, 4000)
Nuevo descriptor de socket
fork()
(tcp, host-C, 4000, -, -)
(tcp, host-A, 22, host-C, 4000)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
69
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Conexión con TCP

Servidor cliente
(host-A, 22) (host-B, 1500)

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

Conexión

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


cliente
(host-C, 4000)
Conexión
(tcp, host-C, 4000, host-A, 22)
(tcp, host-A, 22, host-C, 4000)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
70
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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


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)
 Ejemplos (nivel SOL_SOCKET):
 SO_REUSEADDR: permite reutilizar direcciones

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
71
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
¿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 tránsito en la red
int val = 1;
setsockopt(sd, SOL_SOCKET, SO_REUSEADDR,
(char *) &val, sizeof(int));

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
72
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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));
printf(“%d\n”, size)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
73
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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,
sizeof(option));

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
74
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Sockets de Java
 El paquete java.net de Java permite crear sockets TCP/IP

 Clases para sockets datagrama:


 DatagramSocket
 DatagramPacket

 Clases para sockets stream:


 ServerSocket
 Socket

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
75
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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/DatagramPacket.html

 DatagramSocket:
 Implementa un socket que se puede utilizar para enviar o recibir
datagramas.
 Constructor: DatagramSocket
 Métodos: send, receive, close, setSoTimetout, getSoTimeout,...
 http://download.oracle.com/javase/6/docs/api/java/net/DatagramSocket.html

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
76
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Sockets datagrama
Proceso emisor Proceso receptor
Vector de bytes Vector de bytes

Dirección del
receptor

Objeto DatagramPacket Objeto DatagramPacket

send
receive
Objeto DatagramSocket Objeto DatagramSocket

Referencia a objeto
Flujo de datos
F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
77
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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/ServerSocket.html

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
78
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo XI:
Modelo de comunicación
Servidor

Cliente ServerSocket(puerto);

socket(host, puerto) accept();

OutputStream InputStream

InputStream OutputStream

close() close()

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
79
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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
 Formato de los datos
 Orden de los bytes: big-endian/little-endian
 Opciones de los sockets
 Protocolo de servicio
 Fiabilidad: Gestión de errores (UDP)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
80
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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

¿Detección de duplicación? No No Si

¿Secuenciamiento? No No Si

¿Flujo de control? No No Si

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
81
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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 servidor

respuesta

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
82
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo VIII:
Programar un servidor y cliente en TCP

Máquina A Máquina B
sumar(5,2)
cliente servidor
5+2

NÚCLEO Resultado = 7 NÚCLEO

RED

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
83
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo VIII: Modelo de comunicación
Proceso servidor

socket()
Proceso cliente
bind()

socket() listen()

Conexión
connect() accept()

Petición
write() read()

Respuesta
read() write()

close() close()

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
84
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

socket()

Proceso cliente
bind()

Ejemplo VIII: Servidor TCP socket()

connect()
Conexión
listen()

accept()

#include <sys/types.h> write()


Petición
read()

#include <sys/socket.h> read()


Respuesta
write()

close() close()

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;

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;
server_addr.sin_port = htons(4200);

bind(sd, &server_addr, sizeof(server_addr));

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
85
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

socket()

Proceso cliente
bind()

Ejemplo VIII: Servidor TCP socket()

connect()
Conexión
listen()

accept()

Petición
write() read()

listen(sd, 5); read()


Respuesta
write()

size = sizeof(client_addr); close() close()

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

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

} /*fin main */

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
86
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

socket()

Proceso cliente
bind()

Ejemplo VIII: Cliente TCP socket()

connect()
Conexión
listen()

accept()

#include <sys/types.h> write()


Petición
read()

Respuesta
#include <sys/socket.h> read() write()

close() close()

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");
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;
server_addr.sin_port = htons(4200);

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
87
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

socket()

Proceso cliente
bind()

Ejemplo VIII: Cliente TCP socket()

connect()
Conexión
listen()

accept()

Petición
write() read()

Respuesta
read() write()

// se establece la conexión close() close()

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

read(sd, &res, sizeof(int)); // recibe la respuesta

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

close (sd);
exit(0);

} /* fin main */

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
88
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo IX:
Programar un servidor y cliente en UDP

Máquina A Máquina B
sumar(5,2)
cliente servidor
5+2

NÚCLEO Resultado = 7 NÚCLEO

RED

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
89
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo IX:
Modelo de comunicación
Proceso servidor

socket()
Proceso cliente
bind()

socket()

Petición
sendto() recvfrom()

Respuesta
recvfrom() sendto()

close() close()

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
90
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

Ejemplo IX: socket()

Proceso cliente

Servidor UDP
bind()

socket()

#include <sys/types.h> Petición


sendto() recvfrom()

#include <sys/socket.h> recvfrom()


Respuesta
sendto()

close() close()

void main(void)
{
int num[2];
int s, res, clilen;
struct sockaddr_in server_addr, client_addr;

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

bind(s, (struct sockaddr *)&server_addr, sizeof(server_addr));

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
91
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

Ejemplo IX: socket()

Proceso cliente

Servidor UDP
bind()

socket()

Petición
sendto() recvfrom()

Respuesta
clilen = sizeof(client_addr); recvfrom() sendto()

close() close()

while (1)
{
recvfrom(s, (char *) num, 2* sizeof(int), 0,
(struct sockaddr *)&client_addr, &clilen);

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

sendto(s, (char *)&res, sizeof(int), 0,


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

} /* fin main */

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
92
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

Ejemplo IX: socket()

Proceso cliente

Cliente UDP
bind()

socket()

Petición
void main(int argc, char *argv[]) sendto()

Respuesta
recvfrom()

recvfrom() sendto()

{ close() close()

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

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;
server_addr.sin_port = htons(7200);

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
93
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Proceso servidor

Ejemplo IX: socket()

Proceso cliente

Cliente UDP
bind()

socket()

bzero((char *)&client_addr, sizeof(client_addr)); Petición


sendto() recvfrom()

client_addr.sin_family = AF_INET; recvfrom()


Respuesta
sendto()

client_addr.sin_addr.s_addr = INADDR_ANY; close() close()

client_addr.sin_port = htons(0);

bind (s, (struct sockaddr *)&client_addr, sizeof(client_addr));

num[0] = 2;
num[1] = 5;

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
94
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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
 Los datos que se reciben de la red deben estar en Host Byte Order

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
95
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo X: Programar un servidor y cliente
usando sockets datagramas de Java

Máquina A Máquina B
sumar(5,2)
cliente servidor
5+2

NÚCLEO Resultado = 7 NÚCLEO

RED

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
96
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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];

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
97
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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;
// 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

out = new DatagramPacket (bsend, bsend.length, server_addr, 2500);


s.send(out);

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
98
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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);

res = dis.readInt();
System.out.println("Datos recibidos " + res);
}
catch (Exception e) {
System.err.println("<<<<<excepcion " + e.toString() );
e.printStackTrace() ;
}
}
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
99
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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;
DatagramPacket in, out;
InetAddress client_addr = null;
int client_port;
byte brecv[] = new byte[100];
byte bsend[] = new byte[100];
int num[], res;

try {
s = new DatagramSocket(2500);
in = new DatagramPacket(brecv, 100); // paquete para recibir la solicitud

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
100
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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];

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
101
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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() ;
}
}
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
102
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Ejemplo XI: Programar un servidor y cliente
usando sockets stream de Java

Máquina A Máquina B
sumar(5,2)
cliente servidor
5+2

NÚCLEO Resultado = 7 NÚCLEO

RED

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
103
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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;
int num[] ; // petición
int res;
try {
serverAddr = new ServerSocket(2500);
}
catch (Exception e){
System.err.println("Error creando socket");
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
104
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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() ;
}
}
}
}
F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
105
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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];

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
106
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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();

sc.close();
System.out.println("La suma es " + res);
}
catch (Exception e){
System.err.println("excepcion " + e.toString() );
e.printStackTrace() ;
}
}
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
107
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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
Crea un proceso
hijo

respuesta
Proceso
hijo

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
108
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Servidores concurrentes con sockets
stream
Proceso servidor

socket()

Proceso cliente
bind()

socket() listen()

Abrir conexión
accept()
connect()
Crear proceso
hijo

Petición
write() read()

Respuesta
read() write()

close() close()

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
109
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Modelo de comunicación con sockets
datagrama
Proceso servidor

socket()
Proceso cliente
bind()

socket()

Petición
sendto() recvfrom()
Crear proceso
Respuesta hijo
recvfrom()
sendto()

close() close()

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
110
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Tipos de servidores concurrentes
 Un proceso servidor concurrente puede crear dos tipos
de procesos:
 Procesos convencionales (fork)
 Procesos ligeros (threads)

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
111
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
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”);
else
if (pid == 0)/* proceso hijo */
{
close (s);
tratar_peticion(sd);
close(sd);
exit(0);
}
close(sd); /* el padre */
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
112
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Procesos concurrentes con fork
 En el modelo anterior el proceso padre no espera la
terminación de los procesos hijos con wait
 Los procesos hijos cuando mueren quedan en estado zombie
(no desaparecen del sistema)
 Para que los procesos hijos no queden zombies se puede
ejecutar en el padre (sólo para UNIX System V):

signal(SIGCHLD, SIG_IGN);

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
113
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Servidores concurrentes con P. ligeros
petcición

servidor
Cliente
Crea thread
de servicio

respuesta

Thread de
servicio

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
114
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Procesos concurrentes con threads
 El servidor crea un socket s y le asocia una dirección
 El cuerpo principal del servidor es:
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
for(;;) {
sd = accept(s, (struct sockaddr *)& &cliente, &len);
pthread_create(&thid, &attr, tratar_peticion, &sd);
}

 La función que ejecuta el proceso ligero es:


void tratar_peticion(int * s) {
int s_local;
s_local = *s;
/* tratar la petición utilizando el descriptor de s_local */
close(s_local);
pthread_exit(NULL);
}

 ¿Es correcta esta solución?


F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
115
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Necesario sincronización
 La solución anterior es incorrecta ya que los procesos padre e
hijo compiten por el acceso al descriptor (sd) devuelto por
accept
 El proceso ligero hijo creado podría usar sd en tratar_petición mientras que un
nuevo sd es asignado en accept
 Condiciones de carrera

 Necesario sincronizar las acciones con mutex y variables


condicionales
 En el proceso servidor principal
 En los procesos ligeros hijos

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
116
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Necesario sincronización
 El proceso ligero principal debe ejecutar:

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

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
117
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Necesario sincronización
 El proceso ligero hijo debe ejecutar:

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

/* tratar la petición utilizando el descriptor s_local */


pthread_exit(NULL);
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
118
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Servidor concurrente en Java (streams)
while (true){
try {
Socket cliente = serverAddr.accept();
new TratarPeticion(cliente).start();
}
catch(Exception e) {
System.err.println("excepcion " + e.toString() );
e.printStackTrace() ;
}
}
}
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
119
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Servidor concurrente en Java (streams)
class TratarPeticion extend Thread {
private Socket sc;

TratarPeticion(Socket s) {
sc = s;
}

public void run() {


// TODO: código del cliente
}

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
120
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.
Bibliografía y ejemplos
 Ejemplos de programas usando sockets:
 Ejemplo de sockets
 Ejemplo de uso de sockets en Java
 http://www.php-es.com/ref.sockets.html
 Sockets en Java
 Programas de ejemplos de sockets y RPC

F. García-Carballeira, Mª. Soledad Escolar, Luis Miguel Sánchez, Fco. Javier García
121
Este obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial-CompartirIgual 3.0 España.

También podría gustarte