Fundamentos de Redes: Control de Flujo TCP, Sockets y Protocolos de Correo

Protocolo TCP: Control de Flujo y Ventana Deslizante

El protocolo TCP implementa un control de flujo mediante el mecanismo de ventana deslizante. Las ventanas de recepción son de tamaño variable y pueden llegar a cerrarse por completo. Esta flexibilidad permite un control de flujo extremo a extremo, gestionado por TCP en función de los recursos disponibles, como la memoria.

Cálculo de Velocidad Máxima de Transmisión en LAN

Considerando una LAN con un Tiempo de Ida y Vuelta (RTT) estimado de 1ms, podemos calcular la velocidad máxima de transmisión (ancho de banda efectivo) necesaria para lograr una utilización del 100% con una única conexión TCP:

  • RTT = 1ms
  • Ventana máxima = 64 KB

La fórmula para calcular el ancho de banda efectivo (BW) es:

BW = (Tamaño de la ventana * 8 bits/byte) / RTT

En este caso:

BW = (64 KB * 8 bits/byte) / 1ms

Para obtener la velocidad en MB/s, realizamos la siguiente conversión:

64 KB = 64 * 1024 bytes

1 ms = 0.001 segundos

Velocidad = (64 * 1024 bytes * 8 bits/byte) / 0.001 segundos

Velocidad ≈ 512 * 10^6 bits/segundo ≈ 64 MB/s

Por lo tanto, la red debe alcanzar una velocidad efectiva de aproximadamente 64 MB/s para utilizar el 100% de su ancho de banda con una única conexión TCP bajo estas condiciones.

Dinámica de la Ventana de Congestión en TCP

A lo largo de una conexión TCP, la ventana de congestión (cwnd) y la ventana de recepción (rwnd) interactúan para determinar el tamaño efectivo de la ventana de transmisión (awnd), que es el mínimo de ambas: awnd = min(cwnd, rwnd).

  • T1 – Recepción de un nuevo ACK válido: La ventana de congestión aumenta exponencialmente (ej. a 8). El resto de parámetros se mantienen constantes.
  • T2 – Recepción de otro ACK válido: La ventana de congestión incrementa (ej. a 9). Si la ventana de recepción es menor, la ventana de transmisión será 9.
  • T3 – Recepción de un segmento con indicación de ventana de recepción de 20 MSS: La ventana de congestión es 10, y la ventana de recepción es 20. La ventana de transmisión será el mínimo, es decir, 10.
  • T4 – Ocurrencia de un timeout: La ventana de congestión se reinicia a 1 (inicio del slow start). El umbral de congestión (ssthresh) se reduce a la mitad (ej. a 5). La ventana de recepción permanece en 20.

Gestión de Sockets en Servidores y Clientes

La Llamada `bind()` en Servidores

En un servidor, la llamada `bind()` es fundamental porque asocia una dirección de socket local y un número de puerto específico a un socket recién creado. Esto permite que el sistema operativo sepa a qué proceso dirigir los paquetes entrantes que llegan a esa dirección IP y puerto.

La Llamada `connect()` en Clientes

En un cliente, al usar `connect()` sobre un socket UDP, se establece una asociación persistente entre el cliente y el servidor. Después de `connect()`, el cliente puede enviar datos sin especificar explícitamente la dirección del servidor en cada datagrama. Además, el socket solo aceptará datagramas provenientes de la dirección del servidor especificada durante `connect()`.

La Llamada `listen()`

La llamada `listen()` pone un socket en modo pasivo, preparándolo para aceptar conexiones entrantes. Es un paso previo necesario antes de `accept()`, y solo se aplica a sockets de tipo `SOCK_STREAM` (TCP).

La Llamada `accept()`

Los servidores utilizan `accept()` para esperar y gestionar las peticiones de conexión de los clientes. Internamente, esta llamada bloquea la ejecución del programa hasta que llega una petición de conexión al socket que está escuchando. Si existen múltiples peticiones encoladas (debido a `listen()`), `accept()` intentará establecer la conexión con la primera de la cola.

Diferencia entre el Socket de Argumento y el Socket Devuelto por `accept()`

No, el socket que se pasa como argumento a `accept()` (el socket de escucha) y el nuevo socket que devuelve `accept()` no tienen la misma dirección de socket. El socket de argumento está configurado para escuchar conexiones entrantes, mientras que el nuevo socket devuelto por `accept()` representa la conexión específica establecida con un cliente particular y se utiliza para la comunicación bidireccional con ese cliente.

Gestión de Múltiples Conexiones en un Servidor

Si un servidor tiene un socket maestro que ha establecido 4 conexiones, para gestionar la entrega de segmentos a cada conexión de manera individual, se suele implementar un servidor concurrente. En este modelo, se crea un nuevo proceso o hilo hijo por cada conexión entrante. El socket maestro se mantiene escuchando nuevas peticiones, mientras que los procesos/hilos hijos se encargan de la comunicación con sus respectivos clientes utilizando sockets dedicados.

Uso de `read()` y `write()` con `SOCK_DGRAM` (UDP)

No. Las llamadas `read()` y `write()` se utilizan típicamente para protocolos orientados a conexión como TCP (`SOCK_STREAM`). Para sockets UDP (`SOCK_DGRAM`), que son sin conexión, se deben usar las funciones sendto() y recvfrom(), ya que estas permiten especificar la dirección de destino y origen en cada operación de envío y recepción.

Diferencias entre `close()` y `shutdown()`

  • close(): Cierra completamente el socket y libera todos los recursos asociados. Una vez llamado, el socket ya no puede ser utilizado.
  • shutdown(): Permite un cierre más controlado de la conexión. Puede cerrar la transmisión en una dirección (solo enviar, solo recibir) o en ambas. El socket en sí no se elimina inmediatamente, permitiendo operaciones residuales si es necesario.

Se utiliza shutdown() en lugar de close() cuando se necesita un control más granular sobre el proceso de cierre de la conexión, por ejemplo, para asegurar que todos los datos pendientes se envíen antes de cerrar completamente la comunicación.

Obligatoriedad de `bind()` en Servidores y Clientes

  • Servidor: Es obligatorio usar `bind()` para asignar un puerto específico al socket. Esto permite a los clientes saber a qué puerto conectarse para acceder al servicio.
  • Cliente: Generalmente no es obligatorio. Si no se llama a `bind()`, el sistema operativo asignará automáticamente una dirección IP local y un número de puerto efímero al socket cuando se establezca la conexión (por ejemplo, al llamar a `connect()` o al enviar el primer paquete).

Servidores sin Conexión vs. Conexión

Se prefiere un servidor sin conexión (UDP) en las siguientes circunstancias:

  • Cuando se requieren difusiones (broadcast) o multidifusiones (multicast), ya que estas operaciones no son eficientes o posibles con TCP.
  • Cuando la sobrecarga computacional de establecer y mantener conexiones TCP es excesiva para la aplicación.
  • Cuando no se requiere alta fiabilidad o entrega garantizada de paquetes, y la aplicación puede manejar la pérdida de paquetes o retransmisiones a nivel de aplicación.

Identificación de Conexiones TCP con el Mismo Puerto

Aunque dos conexiones TCP puedan compartir el mismo puerto de origen o destino, se diferencian de forma única mediante una combinación de cuatro parámetros clave: dirección IP de origen, puerto de origen, dirección IP de destino y puerto de destino. Esta tupla de 4 elementos define de manera inequívoca cada conexión TCP.

Número Máximo de Sockets Abiertos

  • Servidor Concurrente TCP: Si admite 10 clientes simultáneos, tendrá 11 sockets abiertos: 1 socket maestro (escuchando) y 10 sockets esclavos (uno por cada cliente conectado).
  • Servidor Concurrente UDP: Generalmente solo tiene 1 socket abierto. UDP es sin conexión, por lo que un único socket puede recibir datagramas de múltiples clientes sin necesidad de crear sockets adicionales para cada uno.

Funciones de Selección y Protocolos de Red

La Llamada al Sistema `select()`

La llamada `select()` se utiliza en servidores multiservicio y multiprotocolo para monitorizar múltiples descriptores de archivo (sockets) y determinar cuáles están listos para ser leídos, escritos o si han ocurrido errores. Esto permite al servidor manejar eficientemente eventos de E/S de múltiples fuentes sin bloquearse en una sola operación.

Sí, es necesario su uso en un servidor multiprotocolo para poder determinar qué socket (y por lo tanto, qué protocolo o cliente) está listo para la comunicación, permitiendo así procesar los datos de manera ordenada y eficiente.

Estándar NVT (Network Virtual Terminal)

El estándar NVT define una interfaz de terminal virtual común. Su propósito es estandarizar la representación de datos y comandos entre sistemas con diferentes conjuntos de caracteres y convenciones. Cuando un cliente Telnet se conecta a un servicio, traduce sus datos al formato NVT antes de enviarlos por la red. El servidor, al recibir los datos, los decodifica del formato NVT a su propio formato nativo.

Uso de Cliente Telnet para Otros Servicios

Utilizar un cliente Telnet para acceder a servicios como SMTP o POP3 es posible y común para propósitos de prueba y depuración. Permite interactuar directamente con el servidor enviando comandos y observando las respuestas. Por ejemplo, `$telnet obelix 25` se usaría para conectarse al servidor SMTP en la máquina `obelix` en el puerto 25.

Manejo de Puntos en Telnet y SMTP

Si un cliente Telnet, al enviar un mensaje de correo electrónico vía SMTP, añade un punto al final de una línea que ya lo contenía (una posible interpretación errónea de la especificación), el servidor SMTP está diseñado para detectar y eliminar ese punto adicional al procesar el mensaje, asegurando que el contenido original no se modifique incorrectamente.

Envío de Correo Electrónico con Telnet (Entrega Directa)

Para enviar un correo electrónico a `alumnos@alu.umh.es` usando Telnet y el mecanismo de entrega directa (sin tener cuenta en un servidor de correo accesible), se seguirían estos pasos:

  1. Obtener la dirección IP del MTA (Mail Transfer Agent) más cercano mediante una consulta DNS (ej. `nslookup smtp.servidor.es`).
  2. Conectarse al servidor SMTP usando Telnet:telnet smtp.servidor.es 25
  3. Iniciar la sesión SMTP con el comando `HELO` o `EHLO` (ej. `HELLO local.domain.com`).
  4. Especificar el remitente: `MAIL FROM:<>` (se puede usar una dirección vacía si no se tiene una cuenta).
  5. Especificar el destinatario: `RCPT TO:`
  6. Enviar el cuerpo del mensaje:DATA. A continuación, se escribe el contenido del correo, línea por línea.
  7. Finalizar el mensaje: Se envía un punto en una línea (`.`) para indicar el fin del cuerpo del mensaje.
  8. Terminar la sesión SMTP: `QUIT`

Reconocimiento de Fin de Respuesta del Servidor SMTP

Un cliente SMTP sabe que ha terminado la respuesta del servidor cuando la línea de respuesta comienza con un código de estado de tres dígitos seguido de un espacio en blanco (ej. `250 OK`). Si la respuesta es multilínea, el servidor utiliza un guion después de los tres dígitos en las líneas intermedias (ej. `354 Start mail input; end with .`) y un espacio en blanco en la última línea para indicar que la respuesta ha concluido.

Separación de Protocolos para Correo: SMTP y POP3

Se utilizan dos protocolos (SMTP y POP3) en lugar de uno solo para el correo electrónico debido a sus funciones distintas:

  • SMTP (Simple Mail Transfer Protocol): Se encarga exclusivamente de la tarea de envío de correos electrónicos entre servidores y desde clientes a servidores.
  • POP3 (Post Office Protocol version 3): Se utiliza para que los clientes lean y descarguen los correos electrónicos de su buzón en el servidor a su máquina local.

POP3 opera en tres fases:

  1. Autorización: El cliente se autentica en el servidor.
  2. Transferencia: El cliente recupera o manipula los mensajes del buzón.
  3. Actualización: Los cambios (como mensajes marcados para borrado) se aplican al finalizar la sesión.

Comandos POP3 por Fase

  • Autorización: Comandos como `USER` y `PASS` para la autenticación.
  • Transferencia: Comandos como `LIST` (listar mensajes), `RETR` (recuperar mensaje), `DELE` (marcar para borrar), `TOP` (ver cabeceras y N líneas del cuerpo).
  • Actualización: Comandos como `RSET` (deshacer borrados) y `QUIT` (finalizar sesión y aplicar cambios).

Interacción con Servicios de Red Usando Telnet

Comando `telnet localhost 37`

  • a) Uso del comando: Se ha utilizado para conectarse al servidor de tiempo (TIME) que escucha en el puerto 37 en la máquina local (`localhost`).
  • b) Significado de «È*ý»: Estos caracteres representan la información del servicio de tiempo devuelta por el servidor. La codificación específica puede depender de la configuración de la terminal y del servidor, pero es la representación de la hora actual.
  • c) Comando alternativo: Si se buscara un servicio que devolviera una cadena de caracteres más descriptiva o un formato diferente, se podría invocar un comando para otro servicio de red, o si existiera un servicio específico para obtener la hora en un formato textual, se usaría ese. Por ejemplo, si hubiera un servicio `PAYTIME` que devolviera texto, se usaría ese.

Uso de US-ASCII-7 en Aplicaciones de Red

El conjunto de caracteres US-ASCII de 7 bits se usa frecuentemente en aplicaciones de red porque:

  • Es el lenguaje base entendido por el estándar NVT, facilitando la interoperabilidad entre sistemas con diferentes codificaciones de caracteres.
  • Es un subconjunto común y simple que garantiza la compatibilidad entre la mayoría de los sistemas y dispositivos de red.
  • Reduce la complejidad y el tamaño de los mensajes al usar un conjunto de caracteres limitado pero suficiente para la mayoría de las comunicaciones de control y datos básicas.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.