PROTOCOLO TCP
Protocolo de Control de Transmisión (TCP).
- En la capa de Transporte: Ofrece maneras
flexibles y de alta calidad para crear comunicaciones de red confiables,
sin problemas de flujo y con un nivel bajo de error.
- Es un protocolo orientado a la conexión,
mantiene un dialogo entre el origen y el destino mientras empaqueta la
información de la capa de aplicación en unidades denominadas segmentos.
Funciones de TCP
En la pila de protocolos TCP/IP, TCP es la
capa intermedia entre el protocolo de internet (IP) y la aplicación. Habitualmente, las
aplicaciones necesitan que la comunicación sea fiable y, dado que la capa IP
aporta un servicio de datagramas no fiable (sin confirmación), TCP añade las
funciones necesarias para prestar un servicio que permita que la comunicación
entre dos sistemas se efectúe libre de errores, sin pérdidas y con seguridad.
Formato de los Segmentos TCP
En el nivel de transporte, los paquetes de bits que constituyen las
unidades de datos de protocolo TCP se llaman "segmentos".
El formato de los segmentos TCP se muestra en el siguiente esquema:
Funcionamiento del protocolo en detalle
Las conexiones TCP se componen de tres etapas:
establecimiento de conexión, transferencia de datos y fin de la conexión. Para
establecer la conexión se usa el procedimiento llamado negociación en tres
pasos (3-way handshake). Para la desconexión se usa una negociación en
cuatro pasos (4-way handshake). Durante el establecimiento de la conexión,
se configuran algunos parámetros tales como el número de secuencia con el fin
de asegurar la entrega ordenada de los datos y la robustez de la comunicación.
Establecimiento
de la conexión
Negociación en tres pasos o Three-way handshake
Aunque es posible que un par de entidades finales
comiencen una conexión entre ellas simultáneamente, normalmente una de ellas
abre un socket en un determinado puerto TCP y se queda a la escucha de nuevas
conexiones. Es común referirse a esto como apertura pasiva, y determina el lado
servidor de una conexión. El lado cliente de una conexión realiza una apertura
activa de un puerto enviando un paquete SYN inicial
al servidor como parte de la negociación en tres pasos. En el lado del servidor
se comprueba si el puerto está abierto, es decir, si existe algún proceso
escuchando en ese puerto. En caso de no estarlo, se envía al cliente un paquete
de respuesta con el bit RST activado, lo que significa el rechazo del intento de
conexión. En caso de que sí se encuentre abierto el puerto, el lado servidor
respondería a la petición SYN válida con un paquete SYN/ACK. Finalmente, el
cliente debería responderle al servidor con un ACK,
completando así la negociación en tres pasos (SYN, SYN/ACK y ACK) y la fase de
establecimiento de conexión.
Es interesante notar que existe un número de secuencia
generado por cada lado, ayudando de este modo a que no se puedan establecer
conexiones falseadas (spoofing).
Transferencia
de datos
Durante la etapa de transferencia de datos, una serie de
mecanismos claves determinan la fiabilidad y robustez del protocolo. Entre
ellos están incluidos el uso del número de secuencia para ordenar los segmentos
TCP recibidos y detectar paquetes duplicados, checksums para detectar errores,
y asentimientos y temporizadores para detectar pérdidas y retrasos.
Durante el establecimiento de conexión TCP, los números
iniciales de secuencia son intercambiados entre las dos entidades TCP.
Estos números de secuencia son usados para identificar los datos dentro del
flujo de bytes, y poder identificar (y contar) los bytes de los datos de la
aplicación. Siempre hay un par de números de secuencia incluidos en todo
segmento TCP, referidos al número de secuencia y al número de
asentimiento. Un emisor TCP se refiere a su propio número de secuencia
cuando habla de número de secuencia, mientras que con el número de asentimiento
se refiere al número de secuencia del receptor. Para mantener la fiabilidad, un
receptor asiente los segmentos TCP indicando que ha recibido una parte del
flujo continuo de bytes. Una mejora de TCP, llamada asentimiento selectivo
(SACK, Selective Acknowledgement) permite a un receptor TCP asentir los
datos que se han recibido de tal forma que el remitente solo retransmita los
segmentos de datos que faltan.
A través del uso de números de secuencia y asentimiento,
TCP puede pasar los segmentos recibidos en el orden correcto dentro del flujo
de bytes a la aplicación receptora. Los números de secuencia son de 32 bits
(sin signo), que vuelve a cero tras el siguiente byte después del 232-1.
Una de las claves para mantener la robustez y la seguridad de las conexiones
TCP es la selección del número inicial de secuencia (ISN, Initial
Sequence Number).
Un checksum de 16 bits, consistente en el complemento
a uno de la suma en
complemento a uno del contenido de la cabecera y datos del segmento TCP,
es calculado por el emisor, e incluido en la transmisión del segmento. Se usa
la suma en complemento a uno porque el acarreo final de ese método puede ser
calculado en cualquier múltiplo de su tamaño (16-bit, 32-bit, 64-bit...) y el
resultado, una vez plegado, será el mismo. El receptor TCP recalcula el
checksum sobre las cabeceras y datos recibidos. El complemento es usado para
que el receptor no tenga que poner a cero el campo del checksum de la cabecera
antes de hacer los cálculos, salvando en algún lugar el valor del checksum
recibido; en vez de eso, el receptor simplemente calcula la suma en complemento
a uno con el checksum incluido, y el resultado debe ser igual a 0. Si es así,
se asume que el segmento ha llegado intacto y sin errores.
El checksum de TCP también cubre los 96 bit de la
cabecera que contiene la dirección origen, la dirección destino, el protocolo y
el tamaño TCP. Esto proporciona protección contra paquetes mal dirigidos por
errores en las direcciones.
El checksum de TCP es una comprobación bastante débil. En
niveles de enlace con una alta probabilidad de error de bit quizá requiera una
capacidad adicional de corrección/detección de errores de enlace. Si TCP fuese
rediseñado hoy, muy probablemente tendría un código de redundancia cíclica (CRC) para
control de errores en vez del actual checksum. La debilidad del checksum está
parcialmente compensada por el extendido uso de un CRC en el nivel de enlace,
bajo TCP e IP, como el usado en el PPP o en Ethernet. Sin
embargo, esto no significa que el checksum de 16 bits es redundante:
sorprendentemente, inspecciones sobre el tráfico de Internet han mostrado que
son comunes los errores de software y hardware[cita requerida] que
introducen errores en los paquetes protegidos con un CRC, y que el checksum de
16 bits de TCP detecta la mayoría de estos errores simples.
Los asentimientos (ACKs o Acknowledgments)
de los datos enviados o la falta de ellos, son usados por los emisores para
interpretar las condiciones de la red entre el emisor y receptor TCP. Unido a
los temporizadores, los emisores y receptores TCP pueden alterar el
comportamiento del movimiento de datos. TCP usa una serie de mecanismos para
conseguir un alto rendimiento y evitar la congestión de la red (la idea es
enviar tan rápido como el receptor pueda recibir). Estos mecanismos incluyen el
uso de ventana deslizante, que controla
que el transmisor mande información dentro de los límites del buffer del
receptor, y algoritmos de control de flujo, tales como el algoritmo de Evitación de la Congestión (congestion
avoidance), el de comienzo
lento (Slow-start), el de retransmisión rápida, el de recuperación rápida (Fast
Recovery), y otros.
Tamaño
de ventana TCP
El tamaño de la ventana de recepción TCP es la cantidad
de datos recibidos (en bytes) que pueden ser metidos en el buffer de
recepción durante la conexión. La entidad emisora puede enviar una cantidad
determinada de datos pero antes debe esperar un asentimiento con la
actualización del tamaño de ventana por parte del receptor.
Un ejemplo sería el siguiente: un receptor comienza con
un tamaño de ventana x y recibe y bytes, entonces su tamaño de ventana será (x
- y) y el transmisor sólo podrá mandar paquetes con un tamaño máximo de datos
de (x - y) bytes. Los siguientes paquetes recibidos seguirán restando tamaño a
la ventana de recepción. Esta situación seguirá así hasta que la aplicación
receptora recoja los datos del buffer de
recepción.
Escalado
de ventana
Para una mayor eficiencia en redes de gran ancho de
banda, debe ser usado un tamaño de ventana mayor. El campo TCP de tamaño de
ventana controla el movimiento de datos y está limitado a 16 bits, es decir, a
un tamaño de ventana de 65.535 bytes.
Como el campo de ventana no puede expandirse se usa un
factor de escalado. La escala de ventana TCP (TCP window scale) es una
opción usada para incrementar el máximo tamaño de ventana desde 65.535 bytes, a
1 Gigabyte.
La opción de escala de ventana TCP es usada solo durante
la negociación en tres pasos que constituye el comienzo de la conexión. El
valor de la escala representa el número de bits desplazados a la izquierda de
los 16 bits que forman el campo del tamaño de ventana. El valor de la escala
puede ir desde 0 (sin desplazamiento) hasta 14. Hay que recordar que un número
binario desplazado un bit a la izquierda es como multiplicarlo en base decimal
por 2.
Fin
de la conexión
Cierre de una
conexión según el estándar.
La fase de finalización de la conexión usa una
negociación en cuatro pasos (four-way handshake), terminando la conexión desde
cada lado independientemente. Cuando uno de los dos extremos de la conexión
desea parar su "mitad" de conexión transmite un paquete FIN, que el
otro interlocutor asentirá con un ACK. Por tanto, una desconexión típica
requiere un par de segmentos FIN y ACK desde cada lado de la conexión.
Una conexión puede estar "medio abierta" en el
caso de que uno de los lados la finalice pero el otro no. El lado que ha dado
por finalizada la conexión no puede enviar más datos pero la otra parte si
podrá.
Puertos TCP
TCP usa el concepto de número de puerto para
identificar a las aplicaciones emisoras y receptoras. Cada lado de la conexión
TCP tiene asociado un número de puerto (de 16 bits sin signo, con lo que
existen 65536 puertos posibles) asignado por la aplicación emisora o receptora.
Los puertos son clasificados en tres categorías: bien conocidos, registrados y
dinámicos/privados. Los puertos bien conocidos son asignados por la Internet Assigned
Numbers Authority (IANA), van del 0 al 1023 y son usados normalmente por
el sistema o por procesos con privilegios. Las aplicaciones que usan este tipo
de puertos son ejecutadas como servidores y se quedan a la escucha de
conexiones. Algunos ejemplos son: FTP (21), SSH (22), Telnet (23), SMTP (25) y HTTP (80).
Los puertos registrados son normalmente empleados por las aplicaciones de
usuario de forma temporal cuando conectan con los servidores, pero también
pueden representar servicios que hayan sido registrados por un tercero (rango
de puertos registrados: 1024 al 49151). Los puertos dinámicos/privados también
pueden ser usados por las aplicaciones de usuario, pero este caso es menos
común. Los puertos dinámicos/privados no tienen significado fuera de la
conexión TCP en la que fueron usados (rango de puertos dinámicos/privados:
49152 al 65535, recordemos que el rango total de 2 elevado a la potencia 16,
cubre 65536 números, del 0 al 65535).
Desarrollo de TCP
TCP es un protocolo muy desarrollado y complejo. Sin
embargo, mientras mejoras significativas han sido propuestas y llevadas a cabo
a lo largo de los años, ha conservado las operaciones más básicas sin cambios
desde el RFC 793,
publicado en 1981. El
documento RFC 1122 (Host
Requirements for Internet Hosts), especifica el número de requisitos de una implementación
del protocolo TCP. El RFC 2581 (Control
de Congestión TCP) es uno de los más importantes documentos relativos a TCP de
los últimos años, describe nuevos algoritmos para evitar la congestión excesiva.
En 2001, el RFC 3168 fue escrito para
describir la Notificación de Congestión Explícita (ECN), una forma de eludir la
congestión con mecanismos de señalización. En los comienzos del siglo XXI, TCP
es usado en el 95% de todos los paquetes que circulan por Internet. Entre
las aplicaciones más comunes que usan TCP están HTTP/HTTPS (World
Wide Web), SMTP/POP3/IMAP (correo electrónico) y FTP (transferencia de ficheros). Su amplia extensión ha sido
la prueba para los desarrolladores originales de que su creación estaba
excepcionalmente bien hecha.
Recientemente, un nuevo algoritmo de control de
congestión fue desarrollado y nombrado como FAST TCP (Fast
Active queue management Scalable Transmission Control Protocol) por los
científicos de Caltech (California Institute of Technology). Es similar a TCP Vegas en
cuanto a que ambos detectan la congestión a partir de los retrasos en las colas
que sufren los paquetes al ser enviados a su destino. Todavía hay un debate
abierto sobre si éste es un síntoma apropiado para el control de la congestión.
PROTOCOLO UDP
Protocolo de Diagrama de
Usuario (UDP).
Permite el intercambio de
diagrama o paquetes de datos con suficiente información sobre el origen,
destino y contenido, sin que se halla realizado una conexión previa.
Es un protocolo mínimo de nivel de transporte orientado a
mensajes documentado en el RFC 768 de la IETF.
UDP proporciona una sencilla interfaz entre la capa de
red y la capa de aplicación. UDP no otorga
garantías para la entrega de sus mensajes (por lo que realmente no se debería
encontrar en la capa 4) y el origen UDP no retiene estados de los mensajes UDP
que han sido enviados a la red. UDP sólo añade multiplexado de aplicación y suma de verificación de la cabecera y
la carga útil. Cualquier tipo de garantías para la transmisión de la
información deben ser implementadas en capas superiores.
+
|
Bits 0 - 15
|
16 - 31
|
0
|
Puerto origen
|
Puerto destino
|
32
|
Longitud del Mensaje
|
Suma de verificación
|
64
|
Datos |
La cabecera UDP consta de 4 campos de los cuales 2 son
opcionales (con fondo rojo en la tabla). Los campos de los puertos fuente y
destino son campos de 16 bits que identifican el proceso de origen y recepción. Ya que
UDP carece de un servidor de estado y el origen UDP no solicita respuestas, el
puerto origen es opcional. En caso de no ser utilizado, el puerto origen debe
ser puesto a cero. A los campos del puerto destino le sigue un campo
obligatorio que indica el tamaño en bytes del datagrama UDP
incluidos los datos. El valor mínimo es de 8 bytes. El campo de la cabecera
restante es una suma de comprobación de 16 bits que abarca una pseudo-cabecera
IP (con las IP origen y destino, el protocolo y la longitud del paquete UDP),
la cabecera UDP, los datos y 0's hasta completar un múltiplo de 16. El checksum
también es opcional en IPv4, aunque generalmente se utiliza en la práctica (en
IPv6 su uso es obligatorio). A continuación se muestra los campos para el
cálculo del checksum en IPv4, marcada en rojo la pseudo-cabecera IP.
bits
|
0
– 7
|
8
– 15
|
16
– 23
|
24
– 31
|
0
|
Dirección
Origen
|
|||
32
|
Dirección
Destino
|
|||
64
|
Ceros
|
Protocolo
|
Longitud
UDP
|
|
96
|
Puerto
Origen
|
Puerto
Destino
|
||
128
|
Longitud
del Mensaje
|
Suma
de verificación
|
||
160
|
Datos |
El protocolo UDP se utiliza por ejemplo cuando se
necesita transmitir voz o vídeo y resulta más importante transmitir con
velocidad que garantizar el hecho de que lleguen absolutamente todos los bytes.
Puertos
UDP utiliza puertos para permitir la comunicación entre
aplicaciones. El campo de puerto tiene una longitud de 16 bits, por lo que el
rango de valores válidos va de 0 a 65.535. El puerto 0 está reservado, pero es
un valor permitido como puerto origen si el proceso emisor no espera recibir
mensajes como respuesta.
Los puertos 1 a 1023 se llaman puertos "bien
conocidos" y en sistemas operativos tipo Unix enlazar con uno de estos
puertos requiere acceso como superusuario.
Los puertos 1024 a 49.151 son puertos registrados.
Los puertos 49.152 a 65.535 son puertos efímeros y son
utilizados como puertos temporales, sobre todo por los clientes al comunicarse
con los servidores.
Código de
ejemplo (Python 3.x)
El siguiente ejemplo muestra cómo usar el protocolo UDP
para una comunicación cliente/servidor:
Servidor:
import socketserver
print("Servidor iniciado...")
class MyUDPHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request[0].strip()
socket = self.request[1]
print("{0} Ha escrito:".format(self.client_address[0]))
print(data)
socket.sendto(data.upper(), self.client_address)
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = socketserver.UDPServer((HOST, PORT), MyUDPHandler)
server.serve_forever()
Cliente (Cambia "localhost" por la dirección IP del servidor):
import socket
import sys
print("Cliente iniciado...")
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(bytes(data + "\n","utf8"), (HOST, PORT))
received = sock.recv(1024)
print("Enviado: {0}".format(data))
print("Recibido: {0}".format(received))
Código de ejemplo (C++)
El siguiente ejemplo muestra cómo usar el protocolo UDP para una comunicación cliente/servidor:
Servidor:
#include <winsock.h>
#include <stdio.h>
#pragma comment(lib,"ws2_32.lib")
const int BufLen = 1024;
int main()
{
WSADATA wsaData;
SOCKET RecvSocket;
sockaddr_in RecvAddr;
int Puerto = 2345;
char RecvBuf[BufLen];
sockaddr_in SenderAddr;
int SenderAddrSize = sizeof(SenderAddr);
WSAStartup(MAKEWORD(2,2), &wsaData);
RecvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Puerto);
RecvAddr.sin_addr.s_addr = INADDR_ANY;
bind(RecvSocket, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr));
recvfrom(RecvSocket,RecvBuf, BufLen,0,(SOCKADDR *)&SenderAddr,&SenderAddrSize);
printf("%s\n",RecvBuf);
closesocket(RecvSocket);
WSACleanup();
}
Cliente (Cambia "127.0.0.1" por la dirección IP del servidor):
#include <winsock.h>
#pragma comment(lib,"ws2_32.lib")
int main()
{
WSADATA wsaData;
SOCKET SendSocket;
sockaddr_in RecvAddr;
int Puerto = 2345;
char ip[] = "127.0.0.1";
char SendBuf[] = "Hola!!!!";
WSAStartup(MAKEWORD(2,2), &wsaData);
SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(Puerto);
RecvAddr.sin_addr.s_addr = inet_addr(ip);
sendto(SendSocket,SendBuf,strlen(SendBuf)+1,0,(SOCKADDR *) &RecvAddr,sizeof(RecvAddr));
WSACleanup();
}
Diferencia entre TCP y UDP
Aunque normalmente nos referimos a Puertos TCP y UDP,
en realidad más que de puertos debemos hablar de protocolos, ya que no
se trata de diferentes tipos de puertos, sino de diferentes protocolos
utilizados para su gestión.
TCP (Transport Control Protocol) y UDP (User Datagram Protocol) son dos protocolos de puertos de comunicaciones que resultan imprescindibles para éstas y que se comportan de forma diferente.
Entre estos dos tipos de protocolos, o más bien entre su comportamiento en cuanto al tratamiento de transmisión de datos se refiere, hay una serie de diferencias que es conveniente conocer. Vamos a ver cuales son esas diferencias:
TCP (Transport Control Protocol) y UDP (User Datagram Protocol) son dos protocolos de puertos de comunicaciones que resultan imprescindibles para éstas y que se comportan de forma diferente.
Entre estos dos tipos de protocolos, o más bien entre su comportamiento en cuanto al tratamiento de transmisión de datos se refiere, hay una serie de diferencias que es conveniente conocer. Vamos a ver cuales son esas diferencias:
UDP: proporciona un nivel de transporte no fiable de
datagramas, ya que apenas añade la información necesaria para la comunicación
extremo a extremo al paquete que envía al nivel inferior. Lo utilizan
aplicaciones como NFS (Network File System) y RCP (comando para copiar ficheros entre ordenadores remotos), pero
sobre todo se emplea en tareas de control y en la transmisión de audio y vídeo
a través de una red. No introduce retardos para establecer una conexión, no
mantiene estado de conexión alguno y no realiza seguimiento de estos parámetros.
Así, un servidor dedicado a una aplicación particular puede soportar más
clientes activos cuando la aplicación corre sobre UDP en lugar de sobre TCP.
TCP: es el protocolo que proporciona un transporte fiable
de flujo de bits entre aplicaciones. Está pensado para poder enviar grandes
cantidades de información de forma fiable, liberando al programador de la
dificultad de gestionar la fiabilidad de la conexión (retransmisiones, pérdida
de paquetes, orden en el que llegan los paquetes, duplicados de paquetes...)
que gestiona el propio protocolo. Pero la complejidad de la gestión de la
fiabilidad tiene un coste en eficiencia, ya que para llevar a cabo las
gestiones anteriores se tiene que añadir bastante información a los paquetes
que enviar. Debido a que los paquetes para enviar tienen un tamaño máximo,
cuanta más información añada el protocolo para su gestión, menos información
que proviene de la aplicación podrá contener ese paquete (el segmento TCP tiene
una sobrecarga de 20 bytes en cada segmento, mientras que UDP solo añade 8
bytes). Por eso, cuando es más importante la velocidad que la fiabilidad, se
utiliza UDP. En cambio, TCP asegura la recepción en destino de la
información para transmitir.
Transmisión de vídeo y voz
UDP es generalmente el protocolo usado en la transmisión
de vídeo y voz a través de una red. Esto es porque no hay tiempo para enviar de
nuevo paquetes perdidos cuando se está escuchando a alguien o viendo un vídeo
en tiempo real.
Ya que tanto TCP como UDP circulan por la misma red, en
muchos casos ocurre que el aumento del tráfico UDP daña el correcto
funcionamiento de las aplicaciones TCP. Por defecto, TCP pasa a un segundo
lugar para dejar a los datos en tiempo
No hay comentarios:
Publicar un comentario