Tema 1 - Centro de Estudios NOVA

Anuncio
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
TEMA 1 – FUNDAMENTOS DE SOCKETS TCP Y UDP
Concepto de UDP
UDP son las siglas de Protocolo de Datagrama de Usuario (en inglés User Datagram Protocol) un protocolo
sin conexión que, como TCP, funciona en redes IP.
UDP/IP proporciona muy pocos servicios de recuperación de errores, ofreciendo en su lugar una manera
directa de enviar y recibir datagramas a través una red IP. Se utiliza sobre todo cuando la velocidad es un
factor importante en la transmisión de la información, por ejemplo, RealAudio utiliza el UDP.
El FTP utiliza TCP/IP, mientras que TFTP utiliza UDP. TFTP son las siglas de Protocolo de Transferencia de
Archivos Triviales (en inglés Trivial File Transfer Protocol), y puesto que es trivial, perder algo de
información en la transferencia no es crucial.
Concepto de TCP
El Protocolo de Control de Transmisión (TCP en sus siglas en inglés, Transmission Control Protocol que fue
creado entre los años 1973 – 1974 por Vint Cerf y Robert Kahn) es uno de los protocolos fundamentales en
Internet. Muchos programas dentro de una red de datos compuesta por ordenadores pueden usar TCP
para crear conexiones entre ellos a través de las cuales enviarse datos. El protocolo garantiza que los datos
serán entregados en su destino sin errores y en el mismo orden en que se transmitieron. También
proporciona un mecanismo para distinguir distintas aplicaciones dentro de una misma máquina, a través
del concepto de puerto (computación). TCP soporta muchas de las aplicaciones más populares de Internet,
incluidas HTTP, SMTP y SSH.
Servicio Orientado a la Conexión
Se dice que un servicio de comunicación entre dos entidades es orientado a conexión cuando antes de
iniciar la comunicación se verifican determinados datos (disponibilidad, alcance, etc.) entre estas entidades
y se negocian unas credenciales para hacer esta conexión más segura y eficiente. Este tipo de conexiones
suponen mayor carga de trabajo a una red (y tal vez retardo) pero aportan la eficiencia y fiabilidad
necesaria a las comunicaciones que la requieran.
Servicio No Orientado a la Conexión
En telecomunicaciones, no orientado a la conexión significa una comunicación entre dos puntos finales de
una red en los que un mensaje puede ser enviado desde un punto final a otro sin acuerdo previo. El
dispositivo en un extremo de la comunicación transmite los datos al otro, sin tener que asegurarse de que
el receptor esté disponible y listo para recibir los datos. El emisor simplemente envía un mensaje dirigido al
receptor. Cuando se utiliza esta forma de comunicación son más frecuentes los problemas de transmisión
que con los protocolos orientado a la conexión y puede ser necesario reenviar varias veces los datos. Los
protocolos no orientados a la conexión son a menudo rechazados por los administradores de redes que
José Antonio Márquez Paredes
[email protected]
Página 1 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
utilizan cortafuegos porque los paquetes maliciosos son más difíciles filtrar. Elprotocolo IP y el protocolo
UDP son protocolos no orientados a la conexión, pero TCP es un protocolo orientado a la conexión. Los
protocolos no orientados a la conexión son descritos generalmente como sin estado porque los puntos
finales no guardan información para recordar una "conversación" de cambios de mensajes. La alternativa al
enfoque no orientado a la conexión es utilizar protocolos orientados a la conexión, que son descritos a
veces como con estado porque pueden seguir una conversación.
Simplex
Sólo permiten la transmisión en un sentido. Un ejemplo típico es el caso de la fibra óptica; en estos casos se
puede recurrir a sistemas en anillo o con doble fibra para conseguir una comunicación completa. Aunque
en la actualidad ya existe la posibilidad de enviar y recibir señal a través de una sola fibra óptica pero en
diferentes longitudes de onda.Una conexión semidúplex (a veces denominada una conexión alternativa o
semi-dúplex) es una conexión en la que los datos fluyen en una u otra dirección, pero no las dos al mismo
tiempo. Con este tipo de conexión, cada extremo de la conexión transmite uno después del otro. Este tipo
de conexión hace posible tener una comunicación bidireccional utilizando toda la capacidad de la línea.
Half Duplex
En ocasiones encontramos sistemas que pueden transmitir en los dos
sentidos, pero no de forma simultánea. Puede darse el caso de una
comunicación por equipos de radio, si los equipos no son full dúplex,
uno no podría transmitir (hablar) si la otra persona está también
transmitiendo (hablando) porque su equipo estaría recibiendo
(escuchando) en ese momento.En radiodifusión, se da por hecho que
todo duplex ha de poder ser bidireccional y simultáneo, pues de esta
manera, se puede realizar un programa de radio desde dos estudios de
lugares diferentes.
Full Duplex
La mayoría de los sistemas y redes de comunicaciones modernos funcionan en modo dúplex permitiendo
canales de envío y recepción simultáneos. Podemos conseguir esa simultaneidad de varias formas:
•
Empleo de frecuencias separadas (multiplexación en frecuencia)
•
Cables separados
Nota: Por definición no deben existir colisiones en Ethernet en el modo <full-duplex> aunque inusualmente
existen.
José Antonio Márquez Paredes
[email protected]
Página 2 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Conceptos del Protocolo TCP
EL SERVIDOR
Para proporcionar servicio debe disponer de:
•
Dirección IP del servidor.
•
Servicio que queremos crear / utilizar: Estos números son enteros normales y van de 1 a 65535. Los
número bajos, desde 1 a 1023 están reservados para servicios habituales de los sistemas operativos
(www, ftp, mail, ping, etc). El resto están a disposición del programador
José Antonio Márquez Paredes
[email protected]
Página 3 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Pasos a realizar:
•
Apertura de un socket, mediante la función socket(). Esta función devuelve un descriptor de fichero
normal, como puede devolverlo open(). La función socket() no hace absolutamente nada, salvo
devolvernos y preparar un descriptor de fichero que el sistema posteriormente asociará a una
conexión en red.
•
Avisar al sistema operativo de que hemos abierto un socket y queremos que asocie nuestro
programa a dicho socket. Se consigue mediante la función bind(). El sistema todavía no atenderá a
las conexiones de clientes, simplemente anota que cuando empiece a hacerlo, tendrá que
avisarnos a nosotros. Es en esta llamada cuando se debe indicar el número de servicio al que se
•
quiere atender.
Avisar al sistema de que comience a atender dicha conexión de red. Se consigue mediante la
función listen(). A partir de este momento el sistema operativo anotará la conexión de cualquier
cliente para pasárnosla cuando se lo pidamos. Si llegan clientes más rápido de lo que somos
capaces de atenderlos, el sistema operativo hace una "cola" con ellos y nos los irá pasando según
vayamos pidiéndolo.
•
Pedir y aceptar las conexiones de clientes al sistema operativo. Para ello hacemos una llamada a la
función accept(). Esta función le indica al sistema operativo que nos dé al siguiente cliente de la
cola. Si no hay clientes se quedará bloqueada hasta que algún cliente se conecte.
•
Escribir y recibir datos del cliente, por medio de las funciones write() y read(), que son exactamente
las mismas que usamos para escribir o leer de un fichero. Obviamente, tanto cliente como servidor
deben saber qué datos esperan recibir, qué datos deben enviar y en qué formato. Puedes ver cómo
•
se pueden poner de acuerdo en estos mensajes en el apartado de mensajes.
Cierre de la comunicación y del socket, por medio de la función close(), que es la misma que sirve
para cerrar un fichero.
EL CLIENTE
Los pasos que debe seguir un programa cliente son los siguientes:
•
Apertura de un socket, como el servidor, por medio de la función socket()
•
Solicitar conexión con el servidor por medio de la función connect(). Dicha función quedará
bloqueada hasta que el servidor acepte nuestra conexión o bien si no hay servidor en el sitio
indicado, saldrá dando un error. En esta llamada se debe facilitar la dirección IP del servidor y el
número de servicio que se desea.
•
Escribir y recibir datos del servidor por medio de las funciones write() y read().
•
Cerrar la comunicación por medio de close().
José Antonio Márquez Paredes
[email protected]
Página 4 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Funciones TCP
sockfd = socket ( int dominio, int tipo, int protocolo );
sockfd
Es el descriptor de socket devuelto. Luego se utilizará para conectarse, recibir conexiones, enviar y recibir
datos, etc.
Retorna un descriptor de socket, que es tipo int.
Si hubo algún error, socket() retorna -1 y la variable global errno se establece con un valor que indica el
error que se produjo ( ver man 3 perror).
dominio
El dominio de comunicación nos dice donde se encuentran los procesos que se van a intercomunicar.
Si los procesos están en el mismo sistema, el dominio de comunicación será AF_UNIX, si los procesos están
en distintos sistemas y estos se hallan unidos mediante una red TCP/IP, el dominio de comunicación será
AF_INET.
Cabe aclarar que existen otros dominios de comunicación.
Los sockets no se han diseñado solamente para TCP/IP. La idea original fue que se usase la misma interfaz
también para distintas familias de protocolos.
En esta introducción solo trataremos el dominio AF_INET.
Algunos dominios:
•
AF_INET ( unidos mediante una red TCP/IP).
•
AF_UNIX (en el mismo sistema).
Otros dominios.
Para este tutor siempre será AF_INET.
tipo
Podrá ser SOCK_STREAM o SOCK_DGRAM o SOCK_RAW.
protocolo
0 (cero, selecciona el protocolo más apropiado).
José Antonio Márquez Paredes
[email protected]
Página 5 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
int bind(int sockfd, struct sockaddr *my_addr, int addrlen)
El
socket
se
crea
sin
nombre,
debemos
asignarle
uno
para
poder
recibir
conexiones.
bind () se utiliza para darle un nombre al socket, osea una dirección IP y número de puerto del host local
por donde escuchará, al especificar una IP del host local le estamos diciendo por cual interfaz física
escuchará (el sistema puede tener varias interfaces ethernet, ppp, etc).
Es necesario llamar a bind() cuando se está programando un servidor.
Cuando se está programando un cliente generalmente no se utiliza esta función, el kernel le asignará al
socket la dirección IP y número de puerto disponible al llamar a ciertas funciones, por ejemplo cuando
llamamos a connect() para conectarnos con un sistema remoto.
En el servidor es necesario llamar a bind() debido a que el número de puerto debe ser conocido para que
los clientes puedan conectarse. Por ejemplo si estamos programando un servidor de telnet debemos llamar
a bind() para asignarle al socket el puerto 23.
En la aplicación cliente se puede llamar a bind() y asignarle un número de puerto, pero no es necesario
porque nadie va a tratar ni podra conectarse con él.
•
sockfd:
Es el descriptor de socket devuelto por la función socket().
•
my_addr:
Es un puntero a una estuctura sockaddr que contiene la IP del host local y el número de puerto que
se va a asignar al socket.(Mas abajo se detalla).
•
addrlen:
Debe ser establecido al tamaño de la estuctura sockaddr. sizeof(struct sockaddr).
Ejemplo :
int sockfd;
struct sockaddr_in servaddr;
sockfd = socket (AF_INET, SOCK_STREAM, 0);
if (sockfd <= 0){
printf ("Error\n");
exit(1);
}
bzero(&servaddr, sizeof(struct sockaddr_in));
servaddr.sin_family = AF_INET;
servaddr.sin_port htons(PUERTO);
servaddr.sin_addr.s_addr =htonl(INADDR_ANY);
if (bind (sockfd,(struct sockaddr *)&servaddr, sizeof(struct sockaddr_in))<0){
printf ("Error\n");
exit(1);
}
José Antonio Márquez Paredes
[email protected]
Página 6 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Estructuras necesarias para la función bind.
struct sockaddr{
unsigned short sa_family; // AF_*
char sa_data[14]; // Direccion de protocolo.
};
Almacena la dirección de protocolo para muchos tipos de protocolos.
• sa_family puede ser AF_INET, AF_UNIX u otros dominios
• sa_data contiene la dirección IP y número de puerto asignado al socket.
struct in_addr{
unsigned long int s_addr; // Dirección local a la que se asigna el socket
}
struct sockaddr_in {
short int sin_family; // AF_INET
unsigned short sin_port; // Numero de puerto.
struct in_addr sin_addr; // Dirección IP.
unsigned char sin_zero[8]; // Relleno.
};
Se creó la esctuctura sockaddr_in para el caso de internet, para poder referenciar los elementos de forma
más fácil.
• sin_family sera AF_INET. No debe convertirse a network byte order porque es solo usado por el
kernel y no es enviado por la red.
• sin_port (número de puerto) deberá estar en network byte order, osea habrá que usar htons().
• sin_addr (dirección IP) deberá estar en network byte order, osea habrá que usar htons().
• sin_zero se utiliza para rellenar la estructura a la longuitud de sockaddr, debe estar inicializada a
cero con la función bzero(). Ver la página del manual
Los punteros a la estructura sockaddr_in deben ser precedidos con un cast tipo * struct sockaddr antes de
pasarlos como parámetros a funciones.
int sockfd;
struct sockaddr_in servaddr;
sockfd = socket (AF_INET, SOCK_STREAM, 0);
if (sockfd <= 0){
printf ("Error\n");
exit(1);
}
bzero(&servaddr, sizeof(struct sockaddr_in));
servaddr.sin_family = AF_INET;
servaddr.sin_port htons(PUERTO);
servaddr.sin_addr.s_addr= =inet_addr(“10.12.110.57);
if (bind(sockfd, (struct sockaddr *)& servaddr, sizeof(struct sockaddr_in))<0){
printf ("Error\n");
exit(1);
}
José Antonio Márquez Paredes
[email protected]
Página 7 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Funciones utiles para programación con socket
Ordenación de bytes
•
•
Host byte order (little-endian): Byte menos significativo primero
Network byte order (big-endian): Byte más significativo primero
Todos los campos de socketaddr_in han de almacenarse en Network byte order
Network Byte Order & Host Byte Order
Cuando se estan enviando datos por algun tipo de red, estos deben de viajar en un orden tal, que
puedan ser leidos, por lo regular se convierten al tipo Network Byte Order (Orden de Byte de Red), y
cuando esos datos se procesan en un ordenador se deben de convertir a Host Byte Order (Orden de
Byte de Red). Esto se puede hacer con funciones predefinidas de las API de Socket como son:
•
•
•
•
htons() -> ``Nodo a variable corta de Red''
htonl() -> ``Nodo a variable larga de Red''
ntohs() -> ``Red a variable corta de Nodo''
ntohl() -> ``Red a variable larga de Nodo''
int inet_aton(const char *cp, struct in_addr *inp);
Convierte la dirección de Internet cp desde la notación estándar de números y puntos a la representación
binaria, y la guarda en la estructura a la que apunte inp. Devuelve no-cero si la dirección es válida, cero si
no.
struct sockaddr_in servaddr;
inet_aton("10.0.0.1", &servaddr.sin_addr); // almacena IP en servaddr
in_addr_t inet_addr(const char *cp);
La función inet_addr() convierte la dirección de Internet cp desde la notación de números y puntos a la de
datos binarios en orden de bytes del ordenador local. Si la entrada no es válida, devuelve INADDR_NONE
(usualmente -1). Ésta es una interfaz obsoleta a inet_aton, descrita anteriormente; es obsoleta porque -1 es
una dirección válida (255.255.255.255), e inet_aton porporciona una manera más clara para indicar que ha
ocurrido un error.
struct sockaddr_in servaddr;
servaddr.sin_addr.s_addr = inet_addr("128.105.40.13");
José Antonio Márquez Paredes
[email protected]
Página 8 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
in_addr_t inet_network(const char *cp);
La función inet_network() extrae el número de red en orden de bytes de red desde la dirección cp a la
notación de números y puntos. Si la entrada es inválida, devuelve -1.
char *inet_ntoa(struct in_addr in);
La función inet_ntoa() convierte la dirección de Internet in dada en orden de bytes de red a una cadena de
caracteres en la notación estándar de números y puntos. La cadena se devuelve en un búfer reservado
estáticamente, que será sobreescrito en siguientes llamadas.
// if added to the above inet_addr() code, this would print "128.105.40.13":
char *s = inet_ntoa(destAddr.sin_addr);
printf("dotted decimal address is %s\n", s);
struct in_addr inet_makeaddr(int net, int host);
La función inet_makeaddr() construye una dirección de Internet en orden de bytes de red combinando el
número de red net con la dirección local host en la red net, ambas en orden de bytes de ordenador local.
in_addr_t inet_lnaof(struct in_addr in);
La función inet_lnaof() devuelve la parte del ordenador local de la dirección de Internet in. La dirección de
ordenador local se devuelve en orden de bytes de ordenador local.
in_addr_t inet_netof(struct in_addr in);
La función inet_netof() devuelve la parte de número de red de la dirección de Internet in. El número de red
se devuelve en orden de bytes de ordenador local.
int listen ( int sockfd, int backlog)
Se llama desde el servidor, habilita
Solo se aplica a sockets tipo SOCK_STREAM.
•
•
el
socket
para
que
pueda
recibir
conexiones.
sockfd: Es el descriptor de socket devuelto por la función socket() que será utilizado para recibir
conexiones.
backlog: Es el número máximo de conexiones en la cola de entrada de conexiones. Las conexiones
entrantes quedan en estado de espera en esta cola hasta que se aceptan.
José Antonio Márquez Paredes
[email protected]
Página 9 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
int accept ( int sockfd, void *addr, int *addrlen)
Se utiliza en el servidor, con un socket habilitado para recibir conexiones ( listen() ). Esta función retorna un
nuevo descriptor de socket al recibir la conexión del cliente en el puerto configurado.
La llamada a accept() no retornará hasta que se produce una conexión o es interrumpida por una señal.
•
•
•
sockfd :Es el descriptor de socket habilitado para recibir conexiones.
addr :Puntero a una estructura sockadd_in. Aquí se almacenará informacion de la conexión
entrante. Se utiliza para determinar que host está llamando y desde qué número de puerto.
addrlen :Debe ser establecido al tamaño de la estuctura sockaddr.
struct sockaddr_in remote_addr;
int addrlen;
new_sockfd = accept ( sockfd, &remote_addr, &addrlen);
close ( sockfd)
Finalizan la conexión del descriptor de socket. Despues de utilizar close, el socket queda desabilitado para
realizar lecturas o escrituras.
read (int sockfd, void *buff, int len)
Devuelve longitud de lo leído si lectura OK y -1 si no.
• sockfd: descriptor de socket.
• buff: direccionamiento al búfer de almacenamiento de la información.
• Len: tamaño del búfer. Para su medición funciones sizeof() y strlen().
Usada por clientes y servidores.
write (int sockfd, void *buff, int len)
Devuelve longitud de lo escrito si escritura OK y -1 si no.
• sockfd: descriptor de socket.
• buff: direccionamiento al búfer de lectura de la información.
• Len: tamaño del búfer. Para su medición funciones sizeof() y strlen().
Usada por clientes y servidores.
int connect(int sockfd, const struct sockaddr *serv_addr, int addrlen);
La función connect solicita poder conectar el socket especificado por sockfd a un socket remoto cuya
direccíon y puerto se especifica en serv_addr. Los parámetros son:
José Antonio Márquez Paredes
[email protected]
Página 10 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
•
•
sockfd: Descriptor del socket creado con anterioridad.
serv_addr: Estructura de datos donde se especifica la dirección y puerto con el que deseamos
establecer la conexión.
• addrlen: Longitud de la estructura de datos anterior.
La función devuelve el valor -1 si error o 0 si su llamada tiene éxito.
Ejemplo Servidor TCP
if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) {
printf ("ERROR \n");
exit(1);
}
servaddr.sin_family= AF_INET;
servaddr.sin_addr.s_addr= htonl (INADDR_ANY);
servaddr.sin_port=htons (SERVER_PORT);
bzero(&servaddr, sizeof (servaddr));
if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)<0){
printf("ERROR \n");
exit (1);
}
listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de los posibles clientes.
clilen=sizeof(cliaddr);
connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el cliente.
read (connfd, datos, strlen(datos)); //Se entiende que es lo primero que se hace.
write (connfd, respuesta, strlen(respuesta)); // Resuelve
close (connfd);
close (listenfd).
Ejemplo Cliente TCP
if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) {
printf ("ERROR \n");
exit(1);
}
servaddr.sin_family= AF_INET;
servaddr.sin_addr.s_addr= inet_addr (SERVIDOR);
servaddr.sin_port=htons (SERVER_PORT);
bzero(&servaddr, sizeof (servaddr));
clilen=sizeof(servaddr);
connfd =connect(listenfd, (struct_sockaddr *) &servaddr, clilen); //Se inicia la conexión.
write (listenfd, peticion, strlen(peticion)); // Se realiza petición
read (listenfd respuesta strlen(respuesta)); //Se entiende que se recibe respuesta
close (listenfd).
José Antonio Márquez Paredes
[email protected]
Página 11 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Características UDP
El Protocolo de datagramas de usuario (UDP) es un estándar TCP/IP que está definido en RFC 768, "User
Datagram Protocol (UDP)". Algunos programas utilizan UDP en lugar de TCP para el transporte de datos
rápido, compacto y no confiable entre hosts TCP/IP.
UDP proporciona un servicio de datagramas sin conexión que ofrece entrega de mejor esfuerzo, lo que
significa que UDP no garantiza la entrega ni comprueba la secuencia de los datagramas. Un host de origen
que necesita comunicación confiable debe utilizar TCP o un programa que proporcione sus propios servicios
de secuencia y confirmación.
Los mensajes UDP están encapsulados y se envían en datagramas IP, como se muestra en la siguiente
ilustración.
UDP y TCP
En general, las diferencias en cómo entregan los datos UDP y TCP son similares a las diferencias entre una
llamada telefónica y una tarjeta postal. TCP funciona como una llamada telefónica, ya que comprueba que
el destino está disponible y preparado para la comunicación. UDP funciona como una tarjeta postal: los
mensajes son pequeños y la entrega es probable, pero no siempre está garantizada.
Normalmente, utilizan UDP los programas que transmiten pequeñas cantidades de datos a la vez o que
tienen requisitos de tiempo real. En estas situaciones, las capacidades de carga pequeña y multidifusión de
UDP (por ejemplo, un datagrama, muchos destinatarios) resultan más apropiadas que TCP.
UDP es notablemente diferente de los servicios y características que proporciona TCP. En la siguiente tabla
se comparan las diferencias en el modo de administrar la comunicación TCP/IP según se utilice UDP o TCP
para el transporte de datos.
UDP
TCP
Servicio sin conexión; no se establece una Servicio orientado a la conexión; se establece una
sesión entre los hosts.
sesión entre los hosts.
UDP no garantiza ni confirma la entrega, y no TCP garantiza la entrega mediante el uso de
secuencia los datos.
confirmaciones y la entrega secuenciada de datos.
Los programas que utilizan UDP son Los programas que utilizan TCP proporcionan la
responsables de proporcionar la confiabilidad seguridad del transporte de datos confiable.
necesaria para el transporte de datos.
UDP es rápido, tiene requisitos de carga TCP es más lento, tiene requisitos de carga mayores y
pequeños y puede admitir la comunicación sólo admite la comunicación punto a punto.
punto a punto y de un punto a varios puntos.
UDP y TCP utilizan puertos para identificar las comunicaciones para cada programa TCP/IP.
José Antonio Márquez Paredes
[email protected]
Página 12 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Recomendaciones de uso UDP/TCP
UDP se utiliza:
• Comunicaciones breves, que no necesiten grandes requisitos de fiabilididad. Ej: DNS
• Comunicaciones con requisitos de tiempo: Tiempo real Video, sonido.
• Comunicaciones que requieren comunicaciones simultaneas entre 1 servidor y varios clientes
• Comunicaciones en las que la fiabilidad esta “garantizada”, como redes locales LAN.
TCDP se utiliza:
• En general, Internet.
• Entornos con condicionantes de riesgo
• Transferencia de ficheros, excepción: TFTP.
• Comunicaciones largar, sin requisitos de tiempo real.
Pasos necesarios para realizar una conexión UDP
EL SERVIDOR
• Abrir un socket con la función socket()
• Asociar el socket a un puerto con bind()
• Leer mensaje con recvfrom().
• Responder mensaje con sendto()
EL CLIENTE
• Abrir un socket con socket()
• Enviar mensaje al servidor con sendto()
• Leer respuesta con recvfrom()
José Antonio Márquez Paredes
[email protected]
Página 13 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Funciones UDP
sockfd = socket ( int dominio, int tipo, int protocolo );
(Ver funciones TCP. Unica diferencia en tipo, que debemos indicar SOCK_DGRAM)
int recvfrom ( int sockfd, void *buf, int len, unsigned int flags, struct sockaddr
*from, int *fromlen )
•
•
•
•
•
•
sockfd : Descriptor socket por donde se recibirán los datos.
buf : Puntero a un buffer donde se almacenarán los datos recibidos.
len : Longitud del buffer buf.
flags : Ver la página del manual de recv(). Normalmente 0
from : Puntero a una estructura sockaddr que contiene la dirección IP y número de puerto del host
origen de los datos.
fromlen : Debe ser inicializado al tamaño de struct sockaddr ( sizeof (struct sockaddr) ).
Si no hay datos a recibir en el socket , la llamada a recvfrom() no retorna (bloquea) hasta que llegan datos,
se puede establecer al socket como no bloqueante (ver: man 2 fcntl ) de manera que cuando no hay datos
para recibir la función retorna -1 y establece la variable errno=EWOULDBLOCK. Más adelante se hablará de
esto.
recvfrom() retorna el numero de bytes recibidos, igual que recv().
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct
sockaddr *to, int tolen)
• sockfd : Descriptor socket por donde se enviarán los datos.
• msg : Puntero a los datos a ser enviados.
• len : Longitud de los datos en bytes.
• flags : Leer : man 2 sendto. Normalmente 0.
• to : Puntero a una estructura sockaddr que contiene la dirección IP y número de puerto destino.
• tolen : Debe ser inicializado al tamaño de struct sockaddr ( sizeof (struct sockaddr) ).
sendto() retorna el número de bytes enviados, el cual puede ser menor que len, igual que en send().
José Antonio Márquez Paredes
[email protected]
Página 14 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Ejemplo UDP – Servidor ECO
#define MAXLINE 256
#define SERVER_PORT 3000
main ( ) {
int sockfd;
struct sockaddr_in, server_addr, cli_addr;
int n;
socklen_t len;
char mess[MAXLINE];
servaddr.sin_family= AF_INET;
servaddr.sin_addr.s_addr= htonl (INADDR_ANY);
servaddr.sin_port=htons (SERVER_PORT);
bzero(&servaddr, sizeof (servaddr));
if ((listenfd = socket(AF_INET,SOCK_DGRAM,0))<= 0) {
printf ("ERROR \n"; exit(1);
}
if ((bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0) {
printf ("ERROR \n"; exit(1);
}
for ( ; ; ) {
clilen=sizeof(cliaddr);
n = recvfrom(listenfd, mess, MAXLINE, 0, (struct sockaddr *) &cliaddr, &clilen);
sendto (listenfd, mess, n, 0, (struct sockaddr *) &cliaddr, len);
};
close (listenfd).
};
José Antonio Márquez Paredes
[email protected]
Página 15 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Ejemplo UDP – Cliente ECO
#define MAXLINE 256
#define SERVER_PORT 3000
main (int argc, char* argv ) {
int sockfd;
struct sockaddr_in server_addr;
int n;
char sendline[MAXLINE], recvline[MAXLINE +1];
servaddr.sin_family= AF_INET;
inet_pton (AF_INET, argv[1], &serveraddr.sin_addr.s_addr);
servaddr.sin_port=htons (SERVER_PORT);
bzero(&servaddr, sizeof (servaddr));
if ((sockfd = socket(AF_INET,SOCK_DGRAM,0))<= 0) {
printf ("ERROR \n"; exit(1);
}
while (fgets (sendline, MAXLINE,stdin) != NULL) {
sendto (sockfd, sendline, MAXLINE, 0, (struct_sockaddr *) &serverddr, sizeof(serveraddr));
n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
recvline [n]=‘\0’; //Terminar texto.
fputs (stdout, recvline, n+1); // Presentacion
};
close (listenfd)
};
int inet_pton(int af, const char *src, void *dst);
inet_pton - Crea una estructura de dirección de red
Esta función convierte la cadena de caracteres src en una estructura de dirección de red de la familia af , y copia la estructura de dirección de red a dst.
Servidor con multiples clientes
En TCP, el proceso consiste en crear múltiples procesos servidores hijos, individuales para cada uno de los
clientes. En general, este proceso es muy ineficiente. Se deben duplicar pilas, recursos, etc.
En UDP, el proceso es considerablemente más sencillo, además es más natural. No se duplican recursos y es
mas eficiente.
José Antonio Márquez Paredes
[email protected]
Página 16 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Pérdida de datagramas
Los errores en los sockets UDP que se producn de forma asíncrona (no temporizadis) no son detectados,
para ello disponemos de una forma de controlarlos mediente el uso de la función connect.
El funcionamiento de connect en UDP es distinto al de TCP ya que no envía ningún paquete de conexión
SYN, lo que realiza es una configuración interna (local) del sistema y vuelve al funcionamiento de la
aplicación.
int connect(int sockfd, const struct sockaddr *serv_addr, int addrlen);
•
•
•
•
Connect configura localmente, dirección y puerto del servidor.
Se genera una nueva familia de sockets, los socket UDP conectados
No se puede especificar nunca más las direcciones destino y puerto destino. Se utiliza write() o
send().
No se utiliza recvfrom. Se utiliza recv() o read()
José Antonio Márquez Paredes
[email protected]
Página 17 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Ejemplo 1: Conexión Cliente – Servidor. Envio de Mensaje de Bienvenida
indicando ip del servidor en el cliente.
SERVIDOR
/* Estos son los ficheros de cabecera usuales */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 3550 /* El puerto que será abierto */
#define BACKLOG 2 /* El número de conexiones permitidas */
main()
{
int fd, fd2; /* los ficheros descriptores */
struct sockaddr_in server; /* para la información de la dirección del servidor */
struct sockaddr_in client; /* para la información de la dirección del cliente */
int sin_size;
if ((fd=socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
printf("error en socket()\n");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(PORT); /* ?Recuerdas a htons() de la sección "Conversiones"? =) */
server.sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY coloca nuestra dirección IP automáticamente
bzero(&(server.sin_zero),8); /* escribimos ceros en el reto de la estructura */
if(bind(fd,(struct sockaddr*)&server, sizeof(struct sockaddr))==-1) {
printf("error en bind() \n");
exit(-1);
}
if(listen(fd,BACKLOG) == -1) {
printf("error en listen()\n");
exit(-1);
}
while(1) {
sin_size=sizeof(struct sockaddr_in);
if ((fd2 = accept(fd,(struct sockaddr *)&client, &sin_size))==-1) {
printf("error en accept()\n");
exit(-1);
}
printf("Se obtuvo una conexión desde %s\n",inet_ntoa(client.sin_addr) ); /* mostrar la IP del cliente */
send(fd2,"Bienvenido a mi servidor.\n",22,0);
/* que envia el mensaje de bienvenida al cliente */
close(fd2);
/* cierra fd2 */
}
}
José Antonio Márquez Paredes
[email protected]
Página 18 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
CLIENTE
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
/* netbd.h es necesitada por la estructura hostent ;-) */
#define PORT 3550
/* El Puerto Abierto del nodo remoto */
#define MAXDATASIZE 100 /* El número máximo de datos en bytes */
int main(int argc, char *argv[])
{
int fd, numbytes;
/* ficheros descriptores */
char buf[MAXDATASIZE]; /* en donde es almacenará el texto recibido */
struct hostent *he;
/* estructura que recibirá información sobre el nodo remoto */
struct sockaddr_in server; /* información sobre la dirección del servidor */
if (argc !=2) {
/* esto es porque nuestro programa sólo necesitará Un argumento, (la IP) */
printf("Uso: %s <Dirección IP>\n",argv[0]);
exit(-1);
}
if ((he=gethostbyname(argv[1]))==NULL){
printf("gethostbyname() error\n");
exit(-1);
}
/* llamada a gethostbyname() */
if ((fd=socket(AF_INET, SOCK_STREAM, 0))==-1){
printf("socket() error\n");
exit(-1);
}
/* llamada a socket() */
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
/* htons() es necesaria nuevamente ;-o */
server.sin_addr = *((struct in_addr *)he->h_addr); /*he->h_addr pasa la información de ``*he'' a "h_addr"
bzero(&(server.sin_zero),8);
if(connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr))==-1){
printf("connect() error\n");
exit(-1);
}
if ((numbytes=recv(fd,buf,MAXDATASIZE,0)) == -1){
printf("Error en recv() \n");
exit(-1);
}
/* llamada a connect() */
/* llamada a recv() */
buf[numbytes]='\0';
printf("Mensaje del Servidor: %s\n",buf); /* muestra el mensaje de bienvenida del servidor =) */
close(fd); /* cerramos fd =) */
}
José Antonio Márquez Paredes
[email protected]
Página 19 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Programa cliente - servidor mediante sockets en C que en la parte
servidor me genera un numero aleatorio entre 1 y 100 y los clientes le
van escribiendo numero y el server comprueba si es mayor, menor o
han acertado...
Cliente.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
int sockfd;
int len;
struct sockaddr_in address;
int result;
char numero;
char respuesta ='1'; //Inicializamos a 1 para que entre en el while
while(respuesta != '0') {
printf("Escribe un número entre 1 y 100: ");
scanf("%s",&numero);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = htons(9734);
len = sizeof(address);
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result == -1) {
perror("oops: client3");
exit(1);
}
write(sockfd, &numero, 1);
//printf("El cliente envia: %c\n",numero);
read(sockfd, &respuesta, 1); //printf("El cliente recibe: %c\n",respuesta);
if (respuesta == '1') {
printf("El número es mayor que %c\n", numero);
}
if (respuesta == '2') {
printf("El número es menor que %c\n", numero);
}
close(sockfd);
}
printf("Has acertado!!! %c era el número!!!\n", numero);
exit(0);
}
José Antonio Márquez Paredes
[email protected]
Página 20 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
Servidor.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
int main() {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(9734);
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
int aleatorio;
aleatorio = (1+rand()%100);
listen(server_sockfd, 5); //Punto A
while(1) {
char numero;
char respuesta;
printf("Servidor esperando peticiones...\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, &client_len);
read(client_sockfd, &numero, 1); //1 un numero de 1 cifra, 2 de 2 cifras
int numeroacomp = atoi(&numero);
if(aleatorio > numeroacomp) {
respuesta = '1'; //Si retorna 1 es que el valor es menor al número del cliente
}else{
if(aleatorio < numeroacomp){
respuesta = '2'; //Si retorna 2 es que el valor es mayor al núm del cliente
}else{
respuesta = '0'; //Si retorna 0 es que el valor es el correcto.
}
}
write(client_sockfd, &respuesta, 1);
close(client_sockfd);
}
exit(0);
}
José Antonio Márquez Paredes
[email protected]
Página 21 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/select.h>
#define LISTENQ 5 // Tamaño de lista de clientes (4 también sería válido)
#define MAXCLIENT 5 // Número máximo de clientes
#define MSG_SIZE 1024 //Tamaño máximo del mensaje de texto
#define SERVER_PORT 3000
int main (int argc, char **argv) {
int i, maxi, maxfd, listenfd, connfd, sockfd, nready;
int client[MAXCLIENT];
ssize_t n;
fd_set rset, allset;
char msg[MSG_SIZE];
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
if ((listenfd = socket(AF_INET,SOCK_STREAM,0))<= 0) {
printf ("ERROR \n"; exit(1);
}
servaddr.sin_family= AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERVER_PORT);
bzero(&servaddr, sizeof (servaddr));
if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)<0) {
printf("ERROR \n"); exit (1);
}
listen (listenfd, LISTENQ); //Preparado para aceptar la entrada de 5 clientes
maxfd=listenfd;
maxi=-1;
for (i=0; i<MAX_CLIENT;i++) //Inicialización del array de clientes
client[i]=-1;
FD_ZERO(&allset); //Inicialización de los conjuntos de descriptores
FD_ZERO(&rset);
FD_SET(listenfd,&allset);
for(;;){
rset=allset;
nready=select (maxfd+1, &rset, NULL,NULL,NULL); //Bloqueo en espera de entradas
if ( FD_ISSET(listenfd, &rset){ //CLIENTE NUEVO
clilen=sizeof(cliaddr);
connfd =accept(listenfd, (struct_sockaddr *) &cliaddr, &clilen); //Se acepta el cliente
for (i=0; i<MAX_CLIENT; i++) //Actualización del array
if (client[i]<0) {
client[i]=connfd;
break;
}
FD_SET(connfd,&allset); //Actualización del conjunto de descriptores
if (connfd > maxfd) //Actualización de variables
maxfd=connfd;
if (i>maxi)
maxi=i;
José Antonio Márquez Paredes
[email protected]
Página 22 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
CENTRO DE ESTUDIOS NOVA - Cartagena
Laboratorio de Software de Comunicaciones
}
if (--nready<=0) continue; //Previsión para más de una interrupción
/* ESPACIO RESERVADO PARA EL PROCESADO DEL SERVIDOR*/
} //Del bucle principal
} //Del main.
Otras Estructuras de Interes
struct hostent *gethostbyname(const char *name);
struct hostent {
char *h_name;
/* official name of host */
char **h_aliases; /* alias list */
int h_addrtype; /* host address type */
int h_length;
/* length of address */
char **h_addr_list; /* list of addresses */
}
struct hostent *hent;
hent = gethostbyname("www.foobar.net");
José Antonio Márquez Paredes
[email protected]
Página 23 de 23 – Tema 1 Fundamentos de Sockets TCP y UDP
Centro de Estudios Nova
Avda. Pintor Pórtela, Esq. Carlos III, 3
30203 Cartagena
Telf.: 868973838-622373838
Descargar