Sunteți pe pagina 1din 33

UNIVERSIDAD NACIONAL AUTONOMA DE NICARAGUA

UNAN-León

Facultad de Ciencias y Tecnologías


Departamento de Computación

APLICACIONES TELEMÁTICAS

TEMA I: PROGRAMACIÓN CON SOCKETS EN


LINUX

Ing. Denis Leopoldo Espinoza Hernández

León, Nicaragua
Introducción

A lo largo de los últimos 30 años se han diseñado numerosas aplicaciones de


red, ingeniosas y extraordinarias.

Estas aplicaciones van desde los correos de solo texto, hasta las aplicaciones
multimedia de hoy en día.

En este tema, abordaremos los aspectos fundamentales de las diferentes


aplicaciones de red.
Principios de los protocolos de la capa de Aplicación

En este tipo de aplicaciones, el software siempre es distribuido (un emisor y


un receptor).
Protocolo de la capa de Aplicación (RFC)

Es importante distinguir entre las aplicaciones de red y los protocolos de la


capa de aplicación.

Un protocolo de la capa de aplicación es únicamente una parte


(aunque importante) de la aplicación de red. (Web-HTTP o FTP-FTP).

En particular, un protocolo de la capa de aplicación define:

• Tipo de mensajes intercambiados.


• Sintaxis de los distintos mensajes.
• La semántica de los campos.
• Las reglas que determinan cuándo y cómo un proceso envía
mensajes y responde a los mensajes.
Elección del Protocolo de Transporte a utilizar

Los protocolos de la capa de transporte son TCP y UDP, cada uno de los
cuales ofrece un servicio diferente.

UDP (Protocolo de Datagrama de Usuario)

El protocolo de transporte UDP equivale a los datagramas:

• Servicio No Orientado a Conexión.


• Servicio no fiable de transporte.
• No incluye mecanismos de control de congestión.
• Es mejor para las aplicaciones en tiempo real.
TCP (Protocolo de Control de Transmisión)

Identifica a lo que normalmente se conoce y se caracteriza por:

• Servicio Orientado a Conexión.


• La conexión es full-duplex.
• Servicio fiable de transporte.
• Incluye mecanismos de control de congestión.
• No es óptimo para aplicaciones en tiempo real
• TCP garantiza el envío de todos los datos, pero no garantiza la
tasa de fallos de envío ni los de retardos experimentados.
Aplicaciones con sus protocolos de aplicación y transporte
Direccionamiento de Procesos

Para que un proceso pueda enviar un mensaje a otro proceso situado en una
máquina remota, se necesitan:

1.El nombre o dirección de la máquina destino.


Dirección IP.

2. El identificador del proceso dentro la máquina.


Puerto TCP o UDP.

Existen ciertos puertos que se encuentran asignados a los protocolos más


conocidos de la capa de aplicación.

Por ejemplo, un servidor Web ocupa el puerto 80.


Agentes de Usuario

El agente de usuario es la Interfaz entre el usuario y la aplicación de red.


(Ejemplo: en HTTP es el navegador Web).

Servicios que necesita una Aplicación


1. Transferencia fiable de datos.
2. Ancho de banda.
3. Temporización.
Aplicaciones con sus protocolos de aplicación y transporte
Comunicación a través de la red (Sockets)

Un socket es una interfaz entre la capa de aplicación y la capa de transporte


del host, sobre la que se construyen en Internet las aplicaciones.
Asociaciones y sockets

Canal de comunicación
1. Protocolo, dirección local, proceso local, dirección remota, proceso
remoto.
2. Como un cable que une dos procesos.

Socket: extremo de un canal


1. Máquina local: protocolo, dirección local, proceso local.
2. Máquina remota: protocolo, dirección remota, proceso remoto.

API de sockets
• Proporciona estructuras de datos y funciones para la programación de
aplicaciones distribuidas.
Establecimiento del canal: socket()

Crea una canal de comunicaciones bidireccional:


#include <sys/types.h>
#include <sys/socket.h>
int socket (int familia, int tipo, int protocolo)
Parámetros
 Familia: AF_INET
 Tipo:
o Orientado a conexión (SOCK_STREAM),
o No orientado a conexión (SOCK_DGRAM)
 Protocolo: 0
 Devuelve identificador del socket (entero no negativo), -1 si error.
 No asocia dirección IP ni puerto.
Establecimiento del canal: bind()

Asigna al socket una dirección IP y un puerto (TCP/UDP) locales


determinados.
#include <sys/types.h>
#include <sys/socket.h>
int bind (int sockfd, (struct sockaddr *) direccion, int longitud)

Parámetros
1. sockfd: identificador socket devuelto por la función socket().
2. direccion: estructura que contiene el puerto y la dirección IP locales
3. longitud = sizeof (direccion)
4. Devuelve -1 en caso de error
Establecimiento del canal: bind()

Estructura sockaddr_in (para IPv4)


struct sockaddr_in {
short sin_family; /* AF_INET */
u_short sin_port; /* puerto TCP/UDP */
struct in_addr sin_addr; /* dirección IP */
char sin_zero[8]; /* 8 bytes ceros */
}

struct in_addr {
u_long s_addr; /* dirección IP */
}
Establecimiento del canal: bind()

Estructura sockaddr genérica


struct sockaddr {
short sa_family; /* AF_xxx */
char sa_data[14]; /* 14 bytes familia */
}
Uso de la estructura:
1. La estructura sockaddr siempre se pasa por referencia (dirección)
2. Siempre va acompañada de su tamaño:
• Sentido aplicación  kernel: paso por valor.
• Sentido kernel  aplicación: paso por referencia.
Establecimiento del canal: bind()

Uso de bind()
1. Obligatorio en el proceso servidor:
Informa al sistema operativo de que todo el tráfico recibido
en un determinado puerto le corresponde.

2. Opcional en el proceso cliente.


3. Si no se especifica puerto (sin_port=0) el SO asigna el primero libre.
4. Si no se especifica dirección IP (sin_addr=INADDR_ANY) se aceptan
conexiones/datagramas por cualquier interfaz local.
Establecimiento del canal: Ejemplo

if ((ds = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {


error("socket");
exit(1);
} Creación del Socket UDP

bzero ((char *) &servidor, sizeof (servidor);


servidor.sin_family = AF_INET; /* familia Internet */
servidor.sin_port = htons (5001); /* Puerto formato red */
servidor.sin_addr.s_addr = inet_addr(“172.29.20.43”);

longitud1 = sizeof(servidor);

if( bind (ds, (struct sockaddr *) &servidor, longitud1) == -1 ){


error("bind");
exit(1);
} Asocia el socket a una dirección IP y puerto
Funciones auxiliares

Inicializar a cero una estructura (e.g. sockaddr_in):


bzero (char * direccion, int long)

Traducir direcciónes IP formato ASCII (xx.xx.xx.xx) a formato de red (y


viceversa):
unsigned long inet_addr (char * dir_ascii)
char * inet_ntoa (struct in_addr dir_red)

Ordenación de bytes
1. unsigned long htonl (x) /* h->n long */
2. unsigned short htons (x) /*h->n short */
3. unsigned long ntohl (x) /* n->h long */
4. unsigned short ntohs (x) /* n->hshort */
Cierre del canal: close()

Cierra el canal de comunicaciones bidireccional creado previamente por


socket:
#include <sys/types.h>
#include <sys/socket.h>
close (int sockfd);

Parámetros
sockfd: descriptor devuelto por socket().
Modo No Orientado a Conexión UDP

El envío datos en UDP se realiza a través de dos funciones que son:

1. sendto: Permite enviar la cantidad de bytes desde un buffer a través de


un socket.

2. recvfrom: Lee desde un socket, la cantidad de bytes especificada y la


almacena en un buffer.
Envío de datagramas con UDP: sendto

Envía datos a través de un socket a un determinado destino


#include <sys/types.h>
#include <sys/socket.h>
int sendto (int sockemisor, char * mensg, int lgmensg, int opcion,
(struct sockaddr *) destino, int lgdest);

Parámetros:
1. sockemisor: descriptor socket origen
2. mensg: datos del datagrama
3. lgmensg: longitud (n° bytes) datos
4. lgdest = sizeof (destino)
5. opcion: 0
6. destino: estructura sockaddr_in que contiene el puerto y la dirección IP

Devuelve n° de bytes transmitidos, -1 en caso de error


Recepción de datagramas con UDP: recvfrom

Espera y lee un datagrama de la cola de recepción asociada a un socket


#include <sys/types.h>
#include <sys/socket.h>
int recvfrom (int sockreceptor, char * mensg, int lgmensg, int opcion,
(struct sockaddr *) origen, int *lgorig);
Parámetros:
1. sockemisor: descriptor socket destino
2. mensg: buffer recepción
3. lgmensg: longitud (n° bytes) buffer
4. lgorig = sizeof (destino)
5. opcion: 0
6. origen: estructura sockaddr_in que almacenará el puerto y la dirección
IP del emisor

Devuelve n° de bytes recibidos, -1 en caso de error


Arquitectura básica del servidor UDP

socket(): crea el canal

bind(): asocia al canal


una dirección IP y un puerto

recvfrom(): recibe
datos de un cliente

sendto(): envía datos al


cliente a través del socket
Arquitectura básica del servidor UDP

socket(): crea el canal

bind(): asocia al canal


una dirección IP y un puerto

sendto(): envía datos al


servidor a través del socket

recvfrom(): recibe
datos de un servidor
Modo Orientado a Conexión TCP

TCP: Servicio orientado a conexión:


 Garantiza orden de entrega mediante números de secuencia (SEQ).
 Garantiza entrega de datos mediante reconocimientos (ACK).
 Retransmisiones controladas (RTT).
 Control de flujo (ventanas TCP, slow-start).

Las aplicaciones cliente/servidor TCP deberán tener en cuenta estas


características:
 Estados del protocolo TCP.
 Establecimiento y terminación de la conexión TCP.
 Tamaños de buffer y sus implicaciones.

Aplicaciones TCP: SMTP, TELNET, SSH, FTP, HTTP, ...


Cola de escucha TCP: listen()

Crea una cola de espera de peticiones de conexión TCP


#include <sys/types.h>
#include <sys/socket.h>
int listen (int ds, int backlog)

Parámetros:
 ds: descriptor socket servidor (socket escucha).
 backlog: número máximo de conexiones (incompletas o establecidas).
Valor recomendado: 5.
Depende del tipo de servidor (concurrente, iterativo) y de la carga
a que esté sometido (servidores muy cargados se recomienda 16).

Devuelve 0 si todo va bien, -1 si error.


Cambia el estado del socket (CLOSED  LISTEN).
Conectar a un servidor: connect()

Establece una conexión TCP entre un cliente y un servidor


#include <sys/types.h>
#include <sys/socket.h>
int connect (int ds,(struct sockaddr *)destino,int lgdest)

Parámetros:
 ds: descriptor socket cliente.
Bind automático. Si no se especifican la dirección y el puerto del
cliente, el kernel toma por defecto la dirección local y un puerto
local libre.
 destino: estructura sockaddr_in que contiene el puerto y la dirección IP
 del servidor.
 lgdest = sizeof (destino).

Devuelve 0 si todo va bien, -1 si error


Cambia el estado del socket:
CLOSED  SYN_SENT
Aceptar una conexión: accept()

Espera a que se inicie una conexión y la completa:


#include <sys/types.h>
#include <sys/socket.h>
int accept (int ds,(struct sockaddr *) cliente,int *lgcli)

Parámetros:
 ds: descriptor socket servidor
 cliente: estructura sockaddr_in en la que el servidor obtiene el puerto y
la dirección IP del cliente.
 lgcli = sizeof (cliente), inicializada.

Devuelve el descriptor de un nuevo socket conectado al cliente, -1 si error


Socket de escucha y sockets conectado.
 Siempre un socket escuchando (LISTEN)
 Al aceptar una conexión, se crea un nuevo socket (ESTABLISHED)
Escritura de datos: write()

Escribe datos de la cola de envío asociada a un socket TCP


#include <sys/types.h>
#include <unistd.h>
int write (int ds, char * buff,int longitud)

Parámetros:
 ds: descriptor socket.
 buff: dirección del mensaje que se envía.
 longitud: longitud del mensaje que se envía.

Devuelve el número de bytes escritos, -1 si error. Como en ficheros


Función propia de sockets: send()
#include <sys/types.h>
#include <sys/socket.h>
int send (int ds, char * buff,int longitud, int flags)
Lectura de datos: read()

Lee datos de la cola de recepción asociada a un socket TCP


#include <sys/types.h>
#include <unistd.h>
int read (int ds,char * buff,int longitud)

Parámetros:
 ds: descriptor socket.
 buff: dirección donde se guarda el mensaje recibido.
 longitud: longitud memoria reservada para guardar el mensaje.

Devuelve el número de bytes escritos, -1 si error. Como en ficheros


Función propia de sockets: recv()
#include <sys/types.h>
#include <sys/socket.h>
int recv (int ds, char * buff,int longitud, int flags)
Arquitectura básica del servidor TCP

socket(): crea el canal

bind(): asocia al canal una


dirección IP y un puerto

listen(): crea la cola

accept(): acepta una petición


y completa la conexión
read(): lee datos del socket

write(): envía datos al cliente


a través del socket
close(): cierra el socket
Dos descriptores de socket:
ds: socket de escucha (cola)
nds: socket de conexión
Arquitectura básica del clienteTCP

Crea canal bidireccional de


socket(): crea el canal
comunicación (socket)

Conecta con el servidor


connect(): solicita la
(connect) conexión al servidor

write(): envía datos al servidor


Envía datos al servidor
a través del socket

Espera a recibir respuesta


del servidor read(): lee datos del socket

Cierra canal de conexión close(): cierra el socket