INTRODUCCIÓN A LA
PROGRAMACIÓN CON SOCKETS
Celeste Campo (
[email protected])
Carlos García Rubio (
[email protected])
PROGRAMACIÓN CON SOCKETS
Pág. 1
ÍNDICE
1.
Introducción.
2. API de sockets:
– Llamadas al sistema
– Estructuras de datos.
3. Esquemas cliente/servidor.
PROGRAMACIÓN CON SOCKETS
Pág. 2
BIBLIOGRAFÍA
• Básica:
– W. R. Stevens: “Unix Network Programming”. Volume 1:
Networking APIs-Sockets and XTI. 1998 (L/S 004.451.9 UNIX
STE ).
– Capítulo 22 de D. E. Comer: “Internetworking with TCP/IP vol I”,
2 Ed. Prentice Hall, 2000.
– Beej's Guide to Network Programming
(http://beej.us/guide/bgnet/pdf/bgnet_A4_2.pdf).
• Complementaria:
– http://www.gnu.org/software/libc/manual/html_node/Sockets.ht
ml
PROGRAMACIÓN CON SOCKETS - INTRODUCCIÓN
Pág. 3
Introducción
• TCP/IP no define el interfaz con los programas de aplicación (API).
– Depende mucho del sistema operativo.
• El interfaz socket, de BSD UNIX, se ha convertido en el estándar
“de facto”.
– A principios de los 80s, ARPA funda un grupo en la Universidad de
California en Berkeley para integrar TCP/IP en el sistema operativo
UNIX.
– El sistema que desarrollaron se conoce como Berkeley UNIX o BSD
UNIX.
– Como parte del proyecto, se define un API C para que las aplicaciones
puedan usar TCP/IP para comunicarse: interfaz socket.
• Comunicación entre procesos (IPC).
• Aparece a partir de la versión 4.1 de BSD
• Se basa en las llamadas de E/S de UNIX.
• En el interfaz socket se basan los APIs de otros sistemas
operativos (como el Windows sockets) y lenguajes de
programación (java, Python…)
PROGRAMACIÓN CON SOCKETS - INTRODUCCIÓN
Pág. 4
Llamadas al sistema en UNIX
• UNIX: sistema operativo de tiempo compartido desarrollado a
principios de los 70s.
• Orientado a procesos:
– Cada proceso se ejecuta con un privilegio.
• Las aplicaciones interactúan con el sistema operativo mediante
llamadas al sistema (“system calls”):
– Cada vez que una aplicación necesita acceder a un servicio del
sistema operativo, lo hace a través de una llamada al sistema.
• Por ejemplo, las operaciones de E/S.
– La llamada se ejecuta con privilegios del sistema operativo.
• Para el programador, una llamada al sistema funciona como una
llamada a una función:
– Se le pasan unos argumentos.
– Realiza una acción.
– Devuelve resultados.
PROGRAMACIÓN CON SOCKETS - INTRODUCCIÓN
Pág. 5
Entrada/Salida
•
Llamadas al sistema para E/S:
– open()
• Prepara el dispositivo o el fichero para hacer la entrada o la salida.
• Devuelve un entero (descriptor de fichero) que se usará en el resto de las llamadas
para hacer referencia a ese dispositivo.
int desc;
desc = open(“filename”, O_RWDR, 0);
– read()
• Lee datos del dispositivo o fichero.
read(desc,buffer,128)
– write()
• Escribe datos en el dispositivo o fichero.
write(desc,buffer,128)
– close()
• Termina el uso de ese dispositivo.
close(desc)
– Otras llamadas:
• create(): crea un fichero.
• lseek(): permite moverse (“saltar”) por un fichero sin tener que leer ni escribir.
• ioctl(): para control del dispositivo (tamaño de buffer, tabla de caracteres, etc.).
PROGRAMACIÓN CON SOCKETS - INTRODUCCIÓN
Pág. 6
Comunicación entre procesos (IPC)
• Sigue una estructura parecida a la Entrada/Salida:
Crear socket
Conectar
Enviar
Recibir
Cerrar socket
PROGRAMACIÓN CON SOCKETS - INTRODUCCIÓN
Pág. 7
Crear el socket
• Se hace con la llamada socket().
Crear socket
Conectar
Enviar
Recibir
Cerrar socket
PROGRAMACIÓN CON SOCKETS - API DE SOCKETS
Pág. 8
Crear el socket: socket()
#include <sys/types.h>
#include <sys/socket.h>
int socket (int domain, int type, int protocol)
•
domain: dominio de aplicación que representa a una familia de protocolos.
– PF_INET: DARPA Internet (TCP/IP). Comunicaciones sobre IPv4.
– PF_INET6: IPv6. Comunicaciones sobre IPv6.
– PF_UNIX: Sistema de ficheros UNIX (pipe).
– PF_PACKET: Packet sockets (Linux).
•
type: tipo de comunicación.
– SOCK_STREAM: fiable y ordenada.
– SOCK_DGRAM: no fiable y desordenada, conservando los límites de los paquetes.
– SOCK_RAW: acceso directo a los protocolos de bajo nivel.
•
protocol: protocolo.
– Para especificar un protocolo concreto cuando varios pueden dar ese servicio.
– Si se da el valor 0, el sistema elige un protocolo adecuado según el tipo.
– getprotocolbyname() devuelve el número de protocolo a partir del nombre del protocolo
mirando en el fichero /etc/protocols
•
Resultado:
– Descriptor del socket que se reutilizará en las siguientes llamadas.
– “-1” si se ha producido un error.
PROGRAMACIÓN CON SOCKETS - API DE SOCKETS
Pág. 9
Crear el socket: clasificación
Llamada
socket(PF_INET,
SOCK_STREAM,
IPPROTO_TCP)
socket(PF_INET,
SOCK_DGRAM,
IPPROTO_UDP)
socket(PF_INET,
SOCK_RAW,
IPPROTO_ICMP)
Tipo
Acceso a:
TCP socket
UDP socket
Raw socket
TCP
UDP
IP
socket(PF_PACKET,
SOCK_RAW,
ETH_P_ALL)
Packet socket
(Raw socket)
Ethernet
(Linux only)
PROGRAMACIÓN CON SOCKETS - API DE SOCKETS
Pág. 10
Estructura de datos por socket
• Al realizar la llamada a socket(), el sistema operativo lo que crea
es una estructura de datos para mantener la información asociada
a esa comunicación.
Tabla de descriptores
(una por proceso)
0:
1:
2:
3:
4:
.
.
.
Estructura de datos
de un socket
familia: PF_INET
servicio: SOCK_STREAM
IP local
IP remota
puerto local
puerto remoto
.
.
.
PROGRAMACIÓN CON SOCKETS - INTRODUCCIÓN
Pág. 11
Conectar el socket
• Consiste en indicar las IP y puertos que se va
a usar en la comunicación.
Crear socket
• Este paso difiere según sea un cliente o
servidor y stream o dgram:
– Servidor stream:
• bind()
• listen()
• accept()
– Cliente stream:
• bind() (opcional)
• connect()
– Servidor dgram:
• bind()
– Cliente dgram:
• No es necesario hacer nada (opcionalmente
se puede hacer bind() y connect())
Conectar
Enviar
Recibir
Cerrar socket
PROGRAMACIÓN CON SOCKETS - INTRODUCCIÓN
Pág. 12
Conectar el socket
• bind()
– Se suele usar sólo en servidor (stream o dgram),
aunque también se puede usar en el cliente.
• Si no se hace se asignan valores por defecto.
– Asigna al socket la dirección IP y puerto locales
• listen()
– Se usa en servidor stream.
– Indica que el socket se va a quedar a la escucha
esperando que un cliente se conecte.
• accept()
– Se usa en servidor stream.
– Cuando un cliente se conecta, nos devuelve un nuevo
socket por el que nos comunicaremos con él.
• connect()
– Se usa en cliente stream.
– Establece conexión con la IP y puerto remoto
indicados.
– También se puede usar opcionalmente en los clientes
dgram.
• No se establece conexión. Simplemente toma nota de la
IP y puerto del otro extremo.
Crear socket
Conectar
Enviar
Recibir
Cerrar socket
PROGRAMACIÓN CON SOCKETS - API DE SOCKETS
Pág. 13
Especificar dirección local: bind()
•
Inicialmente el socket se crea sin dirección origen ni destino:
– En TCP/IP esto significa que no han sido asignados: dirección IP local,
puerto local, dirección IP destino, puerto destino.
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
• sockfd: descriptor del socket.
• my_addr: es un puntero a una estructura sockaddr.
• addrlen: longitud de la estructura anterior.
• Resultado:
– “-1” si se ha producido un error.
PROGRAMACIÓN CON SOCKETS – API DE SOCKETS
Pág. 14
Estructura sockaddr
struct sockaddr {
unsigned short sa_family;
char
sa_data[14];
};
• Mantiene información sobre direcciones de sockets.
• Campos:
– sa_family: familia de direcciones (admite varios valores, como por
ejemplo AF_INET).
– sa_data: dirección y número de puerto para el socket.
PROGRAMACIÓN CON SOCKETS – API DE SOCKETS
Pág. 15
AF_ versus PF_
•
•
•
En la llamada sockets, al hablar de familias de protocolos hemos visto unas
constantes que empiezan por PF_.
– PF_INET, PF_INET6, PF_UNIX, PF_PACKET…
Al hablar de familias de direcciones aparecen constantes que empiezan por AF_.
– AF_INET, AF_INET6…
Ambas constantes están definidas en <sys/socket.h> y en realidad apuntan al
mismo valor.
2
/* Supported address families. */
...
#define AF_INET
...
#define AF_INET6 10
...
/* Protocol families, same as address families. */
...
#define PF_INET
...
#define PF_INET6 AF_INET6
...
AF_INET
•
Por esta razón en la práctica encontraremos mucho código fuente que usa
indistintamente AF_ o PF_.
PROGRAMACIÓN CON SOCKETS – API DE SOCKETS
Pág. 16
Estructura sockaddr_in
struct sockaddr_in {
unsigned short sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
unsigned char
sin_zero[8];
};
struct in_addr {
unsigned long s_addr;
};
• Mantiene información sobre direcciones de sockets (más fácil manejo que la
estructura anterior).
• Campos:
– sin_family: admite varios valores, como AF_INET.
– sin_port: número de puerto para el socket.
– sin_addr: dirección IP para el socket.
– sin_zero: relleno para mantener el mismo tamaño que sockaddr (debe rellenarse a
cero).
• Notas:
– sin_port y sin_addr deben seguir la “ordenación de octetos de la red”.
– Es posible hacer “casting” entre punteros a estructuras sockaddr_in y sockaddr.
PROGRAMACIÓN CON SOCKETS – API DE SOCKETS
Pág. 17
Ordenación de octetos
• Dos posibles ordenaciones de los octetos:
– Primer octeto es el más significativo.
– Primer octeto es el menos significativo.
•
La “ordenación de octetos de la red” sigue la primera ordenación (“Big-
Endian”), pero los ordenadores pueden almacenar sus datos de cualquier
de la dos formas, por lo tanto en algunos casos es preciso realizar
conversiones.
• Todo lo que se envíe por la red debe seguir la “ordenación de la red”:
– Datos que se envían por el socket.
– Algunos campos en determinadas estructuras.
• Métodos de conversión (#include <netinet/in.h>):
– htons(): “Host to Network Short” (short de máquina a short de red).
– htonl(): “Host to Network Lo
Comentarios de: Introducción a la programación con Sockets (0)
No hay comentarios