Descargar

El servicio de transporte


Partes: 1, 2

  1. Servicios proporcionados a las capas superiores
  2. Primitivas del servicio de transporte
  3. Sockets de Berkeley
  4. Elementos de los protocolos de transporte
  5. Direccionamiento
  6. Establecimiento de una conexión
  7. Liberación de una conexión
  8. Control de flujo y almacenamiento en búfer
  9. Multiplexión
  10. Recuperación de caídas
  11. Un protocolo de transporte sencillo
  12. Los protocolos de transporte de internet: UDP
  13. El protocolo de transporte en tiempo real
  14. Los protocolos de transporte de internet: TCP
  15. Aspectos del desempeño

La capa de transporte no es una capa más. Es el corazón de toda la jerarquía de protocolos. La tarea de esta capa es proporcionar un transporte de datos confiable y económico de la máquina de origen a la máquina de destino, independiente de la red o redes físicas en uso. Sin la capa de transporte, el concepto total de los protocolos en capas tendría poco sentido.

Servicios proporcionados a las capas superiores

La meta fundamental de la capa de transporte es proporcionar un servicio eficiente, confiable y económico a sus usuarios, que normalmente son procesos de la capa de aplicación. Para lograr este objetivo, la capa de transporte utiliza los servicios proporcionados por la capa de red. El hardware o software de la capa de transporte que se encarga del trabajo se llama entidad de transporte, la cual puede estar en el kernel (núcleo) del sistema operativo, en un proceso de usuario independiente, en un paquete de biblioteca que forma parte de las aplicaciones de red o en la tarjeta de red.

Así como hay dos tipos de servicio de red, orientado y no orientado a la conexión, hay dos tipos de servicio de transporte. El servicio de transporte orientado a la conexión es parecido en muchos sentidos al servicio de red orientado a la conexión. En ambos casos, las conexiones tienen tres fases: establecimiento, transferencia de datos y liberación (o terminación). El direccionamiento y el control de flujo también son semejantes en ambas capas. Además, el servicio de transporte no orientado a la conexión es muy parecido al servicio de red no orientado a la conexión.

A pesar de que realizan las mismas o casi las mismas funciones en ambas capas, cada una tiene una función diferente. El código de transporte se ejecuta por completo en las máquinas de los usuarios, pero la capa de red, por lo general, se ejecuta en los ruteadores.

Los usuarios no tienen control sobre la capa de red, por lo que no pueden resolver los problemas de un mal servicio usando mejores ruteadores o incrementando el manejo de errores en la capa de enlace de datos. La única posibilidad es poner encima de la capa de red otra capa que mejore la calidad del servicio. Si en una subred orientada a la conexión, a la mitad de una transmisión larga se informa a una entidad de transporte que su conexión de red ha sido terminada de manera abrupta, sin indicación de lo sucedido a los datos actualmente en tránsito, la entidad puede establecer una nueva conexión de red con la entidad de transporte remota. Usando esta nueva conexión de red, la entidad puede enviar una solicitud a su igual preguntando cuáles datos llegaron y cuáles no, y reiniciar a partir de donde se originó la interrupción.

Esencialmente, la existencia de la capa de transporte hace posible que el servicio de transporte sea más confiable que el servicio de red subyacente. La capa de transporte puede detectar y compensar paquetes perdidos y datos alterados. Más aún, las primitivas del servicio de transporte se pueden implementar como llamadas a procedimientos de biblioteca con el propósito de que sean independientes de las primitivas del servicio de red, las cuales podrían variar considerablemente entre las redes.

Gracias a la capa de transporte, es posible escribir programas de aplicación usando un conjunto estándar de primitivas, y que estos programas funcionen en una amplia variedad de redes sin necesidad de preocuparse por lidiar con diferentes interfaces de subred y transmisiones no confiables. Si ninguna red real tuviera fallas, y si todas tuvieran las mismas primitivas de servicio y se pudiera garantizar que nunca jamás cambiaran, tal vez la capa de transporte sería innecesaria. Sin embargo, en el mundo real esta capa cumple la función clave de aislar a las capas superiores de la tecnología, el diseño y las imperfecciones de la subred.

Por esta razón, mucha gente establece una distinción entre las capas 1 a 4. Las cuatro capas inferiores pueden verse como el proveedor del servicio de transporte, y las capas superiores son el usuario del servicio de transporte. Esta distinción entre proveedor y usuario tiene un impacto considerable en el diseño de las capas y pone a la capa de transporte en una posición clave, ya que constituye el límite principal entre el proveedor y el usuario del servicio confiable de transmisión de datos.

Primitivas del servicio de transporte

Para permitir que los usuarios accedan al servicio de transporte, la capa de transporte debe proporcionar algunas operaciones a los programas de aplicación, es decir, una interfaz del servicio de transporte. Cada servicio de transporte tiene su propia interfaz.

El servicio de transporte es parecido al servicio de red, pero hay algunas diferencias importantes. La principal es que el propósito del servicio de red es modelar el servicio ofrecido por las redes reales, con todos sus problemas. Las redes reales pueden perder paquetes, por lo que el servicio de red generalmente no es confiable.

En cambio, el servicio de transporte (orientado a la conexión) sí es confiable. Claro que las redes reales no están libres de errores, pero ése es precisamente el propósito de la capa de transporte: ofrecer un servicio confiable en una red no confiable.

Como nota al margen, la capa de transporte también puede 'proporcionar un servicio no confiable (de datagramas), pero hay muy poco que decir al respecto. Sin embargo, hay algunas aplicaciones que se benefician del transporte no orientado a la conexión, como la computación clienteservidor y la multimedia de flujo continuo.

Una segunda diferencia entre los servicios de red y de transporte es a quién están dirigidos. El servicio de red lo usan únicamente las entidades de transporte. Pocos usuarios escriben sus propias entidades de transporte y, por lo tanto, pocos usuarios o programas llegan a ver los aspectos internos del servicio de red. En contraste, muchos programas ven las primitivas de transporte. En consecuencia, el servicio de transporte debe ser adecuado y fácil de usar.

Primitiva

Paquete enviado

Significado

LISTEN

(ninguno)

Se bloquea hasta que algún proceso intenta la conexión

CONNECT

CONNECTION REQ

Intenta activamente establecer una conexión

SEND

DATA

Envía información

RECEIVE

(ninguno)

Se bloquea hasta que llega un paquete DATA

DISCONNECT

DISCONNECTION REQ

Este lado quiere liberar la conexión

Para ver cómo podrían usarse estas primitivas, considere una aplicación con un servidor y cierta cantidad de clientes remotos. Para comenzar, el servicio ejecuta una primitiva LISTEN, normalmente llamando a un procedimiento de biblioteca que hace una llamada de sistema para bloquear al servidor hasta la aparición de un cliente. Cuando un cliente desea comunicarse con el servidor, ejecuta una primitiva CONNECT. La entidad de transporte ejecuta esta primitiva bloqueando al invocador y enviando un paquete al servidor. En la carga útil de este paquete se encuentra un mensaje de capa de transporte encapsulado, dirigido a la entidad de transporte del servidor.

Como nota al margen, los TPDU (Unidad de Datos del Protocolo de Transporte) son los mensajes enviados de una entidad de transporte a otra. Estas TPDU"s (intercambiadas por la capa de transporte) están contenidas en paquetes (intercambiados por la capa de red). A su vez, los paquetes están contenidos en tramas (intercambiados por la capa de enlace de datos). Cuando llega una trama, la capa de enlace de datos procesa el encabezado de la trama y pasa el contenido del campo de carga útil de la trama a la entidad de red. Esta última procesa el encabezado del paquete y pasa el contenido de la carga útil del paquete a la entidad de transporte.

La llamada CONNECT del cliente ocasiona el envío de una TPDU CONNECTION REQUEST (solicitud de conexión) al servidor. Al llegar ésta, la entidad de transporte verifica que el servidor esté bloqueado en LISTEN (es decir, esté interesado en manejar solicitudes). A continuación desbloqueo el servidor y envía una TPDU CONNECTION ACCEPTED (conexión aceptada) de regreso al cliente. Al llegar esta TPDU, el cliente se desbloqueo y se establece la conexión.

Ahora pueden intercambiarse datos usando las primitivas SEND y RECEIVE. En la forma más simple, cualquiera de las dos partes puede emitir una RECEIVE (bloqueadora) para esperar que la otra parte emita una SEND. Al llegar la TPDU, el receptor se desbloquea y puede procesar la TPDU y enviar una respuesta. Mientras ambos lados puedan llevar el control de quién tiene el turno para transmitir, este esquema funciona bien.

En la capa de transporte, incluso un intercambio de datos unidireccional es más complicado que en la capa de red. También se confirmará (tarde o temprano) la recepción de cada paquete de datos enviado. Asimismo, la recepción de los paquetes que llevan TPDU"s de control se confirmará de manera implícita o explícita. Estas confirmaciones son manejadas por las entidades de transporte usando el protocolo de capa de red, y son transparentes para los usuarios de transporte. De la misma forma, las entidades de transporte necesitarán preocuparse por los temporizadores y las retransmisiones. Los usuarios de transporte no se enteran de ningún aspecto de esta mecánica. Para ellos, una conexión es un conducto de bits confiable: un usuario mete bits en él y mágicamente aparecen en el otro lado. Esta capacidad de ocultar la complejidad es la razón por la cual los protocolos en capas son herramientas tan poderosas.

Cuando ya no se necesita una conexión, debe liberarse para desocupar espacio en las tablas de las dos entidades de transporte. La desconexión tiene dos variantes: asimétrica y simétrica. En la variante asimétrica, cualquiera de los dos usuarios de transporte puede emitir una primitiva DISCONNECT, que resulta en el envío de una TPDU DISCONNECT a la entidad de transporte remota. A su llegada, se libera la conexión.

En la variante simétrica, cada parte se cierra por separado, independientemente de la otra. Cuando una de las partes emite una DISCONNECT, quiere decir que ya no tiene más datos por enviar, pero aún está dispuesta a recibir datos de la otra parte. En este modelo, una conexión se libera cuando ambas partes han emitido una primitiva DISCONNECT.

Sockets de Berkeley

Inspeccionemos brevemente otro grupo de primitivas de transporte, las primitivas de socket usadas en el UNIX de Berkeley para el TCP. En términos generales las primitivas siguen el modelo anterior pero ofrecen más características y flexibilidad.

Primitiva

Significado

SOCKET

Crea un nuevo punto terminal de comunicación

BIND

Adjunta una dirección local a un socket

LISTEN

Anuncia la disposición a aceptar conexiones; indica el tamaño de cola

ACCEPT

Bloquea al invocador hasta la llegada de un intento de conexión

CONNECT

Intenta establecer activamente una conexión

SEND

Envía datos a través de la conexión

RECEIVE

Recibe datos de la conexión

CLOSE

libera la conexión

Las primeras cuatro primitivas de la lista son ejecutadas en ese orden por los servidores. La primitiva SOCKET crea un nuevo punto de comunicación y le asigna espacio en las tablas de la entidad de transporte. Los parámetros de la llamada especifican el formato de direccionamiento que se utilizará, el tipo de servicio deseado y el protocolo. Una llamada SOCKET con éxito devuelve un descriptor de archivo ordinario que se utiliza con las siguientes llamadas, de la misma manera que lo hace una llamada OPEN.

Los sockets recién creados no tienen direcciones de red. Éstas se asignan mediante la primitiva BIND. Una vez que un servidor ha destinado una dirección a un socket, los clientes remotos pueden conectarse a él. La razón para que la llamada SOCKET no cree directamente una dirección es que algunos procesos se encargan de sus direcciones, mientras que otros no lo hacen.

A continuación viene la llamada LISTEN, que asigna espacio para poner en cola las llamadas entrantes por si varios clientes intentan conectarse al mismo tiempo. A diferencia de la llamada LISTEN de la tabla anterior, en el modelo de sockets LISTEN no es una llamada bloqueadora.

Para bloquearse en espera de una conexión entrante, el servidor ejecuta una primitiva ACCEPT. Cuando llega una TPDU solicitando una conexión, la entidad de transporte crea un socket nuevo con las mismas propiedades que el original y devuelve un descriptor de archivo para él. A continuación, el servidor puede ramificar un proceso o subproceso para manejar la conexión en el socket nuevo y regresar a esperar la siguiente conexión en el socket original. ACCEPT regresa un descriptor de archivo normal, que puede utilizarse para leer y escribir de la forma estándar, al igual que con los archivos.

Ahora veamos el cliente. Aquí también debe crearse un socket primero usando la primitiva SOCKET, pero no se requiere BIND, puesto que la dirección usada no le importa al servidor La primitiva CONNECT bloquea al invocador y comienza activamente el proceso de conexión. Al completarse éste, es decir, cuando se recibe la TPDU adecuada del servidor el proceso cliente se desbloqueo y se establece la conexión. Ambos lados pueden usar ahora SEND y RECEIVE para transmitir y recibir datos a través de la conexión dúplex total. Las llamadas de sistema READ y WRITE de UNIX también se pueden utilizar si no son necesarias las opciones especiales de SEND Y RECEIVE.

La liberación de las conexiones a los sockets es simétrica. La conexión se libera cuando ambos lados han ejecutado una primitiva CLOSE.

Elementos de los protocolos de transporte

El servicio de transporte se implementa mediante un protocolo de transporte entre las dos entidades de transporte. En ciertos aspectos, los protocolos de transporte se parecen a los protocolos de enlace de datos. Ambos se encargan del control de errores, la secuenciación y el control de flujo, entre otros aspectos.

Sin embargo, existen diferencias significativas entre los dos, las cuales se deben a diferencias importantes entre los entornos en que operan ambos protocolos. En la capa de enlace de datos, dos ruteadores se comunican directamente mediante un canal físico mientras que, en la capa de transporte, ese canal físico es reemplazado por la subred completa. Esta diferencia tiene muchas aplicaciones importantes para los protocolos.

Por una parte, en la capa de enlace de datos no es necesario que un ruteador especifique el ruteador con el que quiere comunicarse; cada línea de salida especifica de manera única un ruteador en particular. En la capa de transporte se requiere el direccionamiento explícito de los destinos.

Por otro lado, el proceso de establecimiento de una conexión a través de un cable determinado es sencillo: el otro extremo siempre está ahí (a menos que se caiga). Sea como sea, no hay demasiado que hacer. En la capa de transporte, el establecimiento inicial de la conexión es más complicado.

Otra diferencia, entre la capa de enlace de datos y la capa de transporte es la existencia potencial de capacidad de almacenamiento en la subred. Al enviar al ruteador una trama, ésta puede llegar o perderse, pero no puede andar de un lado a otro durante un rato, esconderse en un rincón alejado del mundo y aparecer repentinamente en algún momento inoportuno 30 segundos después. Si la subred usa datagramas y ruteo adaptativo internamente, hay una probabilidad nada despreciable de que un paquete pueda almacenarse durante varios segundos y entregarse después. Las consecuencias de esta capacidad de almacenamiento de paquetes en la subred pueden ser desastrosas y requerir el uso de protocolos especiales.

Una última diferencia entre las capas de enlace de datos y de transporte es de cantidad, más que de tipo. Se requieren búferes y control de flujo en ambas capas, pero la presencia de una cantidad de conexiones grande y dinámicamente variable en la capa de transporte puede requerir un enfoque distinto del que se usa en la capa de enlace de datos. En la capa de transporte, la gran cantidad de conexiones que deben manejarse hace menos atractiva la idea de dedicar muchos búferes a cada una.

Direccionamiento

Cuando un proceso (por ejemplo, un usuario) de aplicación desea establecer una conexión con un proceso de aplicación remoto, debe especificar a cuál se conectará. El método que normalmente se emplea es definir direcciones de transporte en las que los procesos pueden estar a la escucha de solicitudes de conexión. En Internet, estos puntos terminales se denominan puertos. En las redes ATM se llaman AAL-SAP"s. El término genérico es TSAP (Punto de Acceso al Servicio de Transporte). Los puntos terminales análogos de la capa de red (es decir, direcciones de capa de red) se llaman NSAP (Punto de Acceso al Servicio de Red). Las direcciones IP son ejemplos de NSAP"s.

  • 1. Un proceso de servidor de un host (host 1) se enlaza con un TSAP (TSAP 1522) determinado para esperar una llamada entrante. La manera en que un proceso se enlace con una TSAP esta fuera del modelo de red y depende por completo del sistema operativo local.

  • 2. Un proceso de aplicación de otro host (host 2) se enlaza al host 1, por lo que emite una solicitud CONNECT especificando un TSAP (TSAP 1208) como origen y un TSAP (TSAP 1522) como destino. Esta acción da como resultado una conexión de transporte entre el proceso de aplicación host 2 y el servidor del host 1.

  • 3. A continuación el proceso de aplicación envía una solicitud.

  • 4. El proceso de servidor responde.

  • 5. Después se libera la conexión de transporte.

Aunque las direcciones TSAP estables podrían funcionar bien con una cantidad pequeña de servicios clave que nunca cambian (por ejemplo, el servidor Web), en general, los procesos de usuario frecuentemente desean comunicarse con otros procesos de usuario que sólo existen durante un tiempo corto y no tienen una dirección TSAP conocida por adelantado. Si puede haber muchos procesos de servidor, la mayoría de los cuales se usan pocas veces, es un desperdicio tenerlos activados a todos, escuchando en una dirección TSAP estable todo el día.

La manera de solucionar esto se conoce como protocolo inicial de conexión. En lugar de que cada servidor concebible escuche en un TSAP conocido, cada máquina que desea ofrecer servicio a usuarios remotos tiene un servidor de procesos especial que actúa como proxy de los servidores de menor uso. Este servidor escucha en un grupo de puertos al mismo tiempo, esperando una solicitud de conexión. Los usuarios potenciales de un servicio comienzan por emitir una solicitud CONNECT, especificando la dirección TSAP del servicio que desean.

Si no hay ningún servidor esperándolos, consiguen una conexión al servidor de procesos. Tras obtener la solicitud entrante, el servidor de procesos genera el servidor solicitado, permitiéndole heredar la conexión con el usuario existente. El nuevo servidor entonces hace el trabajo requerido, mientras que el servidor de procesos retorna a escuchar solicitudes nuevas.

Aunque el protocolo de conexión inicial funciona bien para aquellos servidores que pueden crearse conforme son necesarios, hay muchas situaciones en las que los servicios existen independientemente del servidor de procesos. Por ejemplo, un servidor de archivos necesita operar en un hardware especial (una máquina con un disco) y no puede simplemente crearse sobre la marcha cuando alguien quiere comunicarse con él.

Para manejar esta situación, se usa con frecuencia un esquema alterno. En este modelo, existe un proceso especial llamado servidor de nombres, o servidor de directorio. Para encontrar la dirección TSAP correspondiente a un nombre de servicio dado, el usuario establece una conexión con el servidor de nombres (que escucha en un TSAP conocido). Entonces el usuario envía un mensaje especificando el nombre del servicio, y el servidor de nombres devuelve la dirección TSAP. Luego el usuario libera la conexión con el servidor de nombres y establece una nueva con el servicio deseado.

En este modelo, al crearse un servicio nuevo, debe registrarse en el servidor de nombres, dando tanto su nombre de servicio como la dirección de su TSAP. El servidor de nombres registra esta información en su base de datos interna por lo que, cuando llegan solicitudes posteriores, sabe las respuestas.

Establecimiento de una conexión

El establecimiento de una conexión es complicado. A primera vista, parecería suficiente con que una entidad de transporte enviara una TPDU CONNECTION REQUEST al destino y esperar una respuesta CONNECTION ACCEPTED. El problema ocurre cuando la red puede perder, almacenar o duplicar paquetes. Este comportamiento causa complicaciones serias.

Por ejemplo una subred que está tan congestionada que las confirmaciones de recepción casi nunca regresan a tiempo, y cada paquete expira y se retransmite dos o tres veces. Suponiendo que la subred usa datagramas internamente, y que cada paquete sigue una ruta diferente. Algunos de los paquetes podrían atorarse en un congestionamiento de tráfico dentro de la subred y tardar mucho tiempo en llegar, es decir, se almacenarían en la subred y reaparecerían mucho después.

Un ejemplo mas concreto de esto sería: un usuario establece una conexión con un banco, envía mensajes indicando al banco que transfiera una gran cantidad de dinero a la cuenta de una persona no del todo confiable y a continuación libera la conexión. Por mala fortuna, cada paquete de la transacción se duplica y almacena en la subred. Tras liberar la conexión, todos los paquetes salen de la subred y llegan al destino en orden, solicitando al banco que establezca una conexión nueva, transfiera el dinero (nuevamente) y libere la conexión. El banco no tiene manera de saber que son duplicados; debe suponer que ésta es una segunda transacción independiente, y transfiere nuevamente el dinero.

El problema es la existencia de duplicados retrasados. Esto puede atacarse de varías maneras, ninguna de las cuales es muy satisfactoria. Una es usar direcciones de transporte desechables. En este enfoque, cada vez que se requiere una dirección de transporte, se genera una nueva. Al liberarse la conexión, se descarta la dirección y no se vuelve a utilizar.

Otra posibilidad es dar a cada conexión un identificador de conexión (es decir, un número de secuencia que se incremente con cada conexión establecida), seleccionado por la parte iniciadora, y ponerlo en cada TPDU, incluida la que solicita la conexión. Tras la liberación de una conexión, cada entidad de transporte podría actualizar una tabla que liste conexiones obsoletas como pares. Cada vez que entrara una solicitud de conexión, podría cotejarse con la tabla para saber si pertenece a una conexión previamente liberada.

Por desgracia, este esquema tiene una falla básica: requiere que cada entidad de transporte mantenga una cierta cantidad de información histórica durante un tiempo indefinido. Si se cae una máquina y pierde su memoria, ya no sabrá qué identificadores de conexión usó.

En lugar de permitir que los paquetes vivan eternamente en la subred, debemos diseñar un mecanismo para eliminar a los paquetes viejos que aún andan vagando por ahí. Si podemos asegurar que ningún paquete viva más allá de cierto tiempo conocido, el problema se vuelve algo más manejable.

El tiempo de vida de un paquete puede restringiese a un máximo conocido usando una de las siguientes técnicas:

  • 1. Un diseño de subred restringido: incluye cualquier método que evite que los paquetes hagan ciclos, combinado con una manera de limitar el retardo por congestionamientos a través de la trayectoria más larga posible.

  • 2. Colocar un contador de saltos en cada paquete: consiste en inicializar el conteo de saltos con un valor apropiado y decrementarlo cada vez que se reenvíe el paquete. El protocolo de red simplemente descarta cualquier paquete cuyo contador de saltos llega a cero.

  • 3. Marcar el tiempo en cada paquete: requiere que cada paquete lleve la hora en la que fue creado, y que los ruteadores se pongan de acuerdo en descartar cualquier paquete que haya rebasado cierto tiempo predeterminado. Además requiere que los relojes de los ruteadores estén sincronizados, lo que no es una tarea fácil a menos que se logre la sincronización externamente a la red

En la práctica, necesitaremos garantizar no sólo que el paquete está eliminado, sino que también lo están todas sus confirmaciones de recepción. Al limitar los tiempos de vida de los paquetes, es posible proponer una manera a prueba de errores de establecer conexiones seguras.

Para resolver el problema de una máquina que pierde toda la memoria acerca de su estado tras una caída, se propone equipar cada host con un reloj de hora del día. Los relojes de los diferentes hosts no necesitan estar sincronizados. Se supone que cada reloj tiene la forma de un contador binario que se incrementa a sí mismo a intervalos uniformes. Además, la cantidad de bits del contador debe ser igual o mayor que la cantidad de bits en los números de secuencia. Por último, y lo más importante, se supone que el reloj continúa operando aun ante la caída del host.

La idea básica es asegurar que nunca estén pendientes al mismo tiempo dos TPDU"s de número idéntico. Cuando se establece una conexión, los bits de orden menor del reloj se usan como número inicial de secuencia (también bits). Por tanto, cada conexión comienza a numerar sus TPDU"s con un número de secuencia inicial diferente. El espacio de secuencia también debe ser lo bastante grande para que, al regresar al principio de los números de secuencia, las TPDU"s viejas con el mismo número de secuencia hayan desaparecido hace mucho tiempo.

Una vez que ambas entidades de transporte han acordado el número de secuencia inicial, puede usarse cualquier protocolo para el control de flujo de datos.

Cuando un host se cae ocurre un problema. Al reactivarse, sus entidades de transporte nos ven dónde estaban en el espacio de secuencia. Una solución es requerir que las entidades de transporte estén inactivas durante T segundos tras una recuperación para permitir que todas las TPDU"s viejas expiren. Sin embargo, en una interred compleja, T puede ser bastante grande, por lo que no es atractiva esta estrategia.

Para evitar requerir T seg de tiempo muerto tras una caída, es necesario introducir una nueva restricción en el uso de números de secuencia.

El método basado en reloj resuelve el problema del duplicado retrasado de las TPDU"s de datos, pero para que este método resulte de utilidad, debe establecerse primero una conexión. Dado que las TPDU"s de control también pueden retrasarse, hay el problema potencial de lograr que ambos lados acuerden el número de secuencia inicial evitando que la conexión se establezca de manera incorrecta.

Para resolver este problema, se desarrolló el acuerdo de tres vías (three-way handshake). Este protocolo de establecimiento no requiere que ambos lados comiencen a transmitir con el mismo número de secuencia, por lo que puede usarse con otros métodos de sincronización distintos del método de reloj global. De esta manera, un duplicado con retardo no causa daño.

Liberación de una conexión

La liberación de una conexión es más fácil que su establecimiento. Hay dos estilos de terminación de una conexión: liberación asimétrica y liberación simétrica. La liberación asimétrica es la manera en que funciona el sistema telefónico: cuando una parte cuelga, se interrumpe la conexión. La liberación simétrica trata la conexión como dos conexiones unidireccionales distintas, y requiere que cada una se libere por separado. La liberación asimétrica es abrupta y puede resultar en la pérdida de datos. Tras establecerse la conexión.

Es obvio que se requiere un protocolo de liberación más refinado para evitar la pérdida de datos. Una posibilidad es usar la liberación simétrica, en la que cada dirección se libera independientemente de la otra. Aquí, un host puede continuar recibiendo datos aun tras haber enviado una TPDU DISCONNECT.

La liberación simétrica es ideal cuando cada proceso tiene una cantidad fija de datos por enviar y sabe con certidumbre cuándo los ha enviado. En otras situaciones, la determinación de si se ha efectuado o no todo el trabajo y si debe terminarse o no la conexión no es tan obvia. Por desgracia, este protocolo no siempre funciona.

Hay un problema famoso que tiene que ver con ese asunto; se llama problema de los dos ejércitos. Suponiendo que En dos cerros que rodean al valle hay ejércitos azules. El ejército blanco es más grande que cualquiera de los dos ejércitos azules por separado, pero juntos éstos son más grandes que el ejército blanco. Si cualquiera de los dos ejércitos azules ataca por su cuenta, será derrotado, pero si los dos atacan simultáneamente obtendrán la victoria.

Los ejércitos azules quieren sincronizar sus ataques. Sin embargo, su único medio de comunicación es el envío de mensajeros a pie a través del valle, donde podrían ser capturados, perdiéndose el mensaje (es decir, tienen que usar un canal de comunicación no confiable). La pregunta es: ¿Existe un protocolo que permita que los ejércitos azules ganen? Supongamos que el comandante del ejército azul núm. 1 envía un mensaje que dice: "Propongo que ataquemos al amanecer del 29 marzo. ¿Qué les parece?" Ahora supongamos que llega el mensaje y que el comandante del ejército azul núm. 2 está de acuerdo, y que su respuesta llega con seguridad al ejército azul núm. 1. ¿Ocurrirá el ataque? Probablemente no, porque el comandante núm. 2 no sabe si su respuesta llegó. Si no llegó, el ejército azul núm. 1 no atacará, y sería tonto de su parte emprender el ataque.

Mejoremos ahora el protocolo haciéndolo un acuerdo de tres vías. El iniciador de la propuesta original debe confirmar la recepción de la respuesta. Suponiendo que no se pierden mensajes, el ejército azul núm. 2 recibirá la confirmación de recepción, pero ahora el que dudará será el comandante del ejército azul núm. 1. A fin de cuentas, no sabe si ha llegado su confirmación de recepción y, si no llegó, sabe que el ejército núm. 2 no atacará. Podríamos probar ahora un protocolo de acuerdo de cuatro vías, pero tampoco ayudaría.

De hecho, puede demostrarse que no existe un protocolo que funcione. Supongamos que existiera algún protocolo. O el último mensaje del protocolo es esencial, o no lo es. Si no lo es, hay, que eliminarlo (así como los demás mensajes no esenciales) hasta que quede un protocolo en el que todos los mensajes sean esenciales. ¿Qué ocurre si el mensaje final no pasa? si se pierde, el ataque no ocurrirá. Dado que el emisor del mensaje final nunca puede estar seguro de su llegada, no se arriesgará a atacar. Peor aún, el otro ejército azul sabe esto, por lo que no atacará tampoco.

Para ver la aplicación del problema de los dos ejércitos a la liberación de conexiones, simplemente sustituya "atacar" por "desconectar". Si ninguna de las partes está preparada para desconectarse hasta estar convencida de que la otra está preparada para desconectarse también, nunca ocurrirá la desconexión.

En la práctica, generalmente estamos más dispuestos a correr riesgos al liberar conexiones que al atacar ejércitos blancos, por lo que la situación no es del todo desesperada.

Control de flujo y almacenamiento en búfer

Habiendo examinado el establecimiento y la liberación de conexiones con algún detalle, veamos ahora la manera en que se manejan las conexiones mientras están en uso. Ya conocemos uno de los aspectos clave: el control de flujo. En algunos sentidos el problema del control de flujo en la capa de transporte es igual que en la capa de enlace de datos, pero en otros es diferente. La similitud básica es que en ambas capas se requiere un esquema en cada conexión para evitar que un emisor rápido desborde a un receptor lento. La diferencia principal es que un ruteador por lo regular tiene relativamente pocas líneas, y que un host puede tener numerosas conexiones. Esta diferencia hace que sea impráctico implementar en la capa de transporte la estrategia de almacenamiento en búfer de la capa de enlace de datos.

En los protocolos de enlace de datos, las tramas se almacenaban en búferes tanto en el ruteador emisor como en el receptor. En la capa de enlace de datos, el lado emisor debe almacenar en búfer las tramas de salida porque cabe la posibilidad de que tengan que retransmitiese. Si la subred provee un servicio de datagramas, la entidad de transporte emisora también debe manejar búferes, por la misma razón, Si el receptor sabe que el emisor almacena en búfer todas las TPDU"s hasta que se confirma su recepción, el receptor podría o no dedicar búferes específicos a conexiones específicas, según considere necesario. Por ejemplo, el receptor podría mantener un solo grupo de búferes compartido por todas las conexiones. Cuando entra una TPDU, se hace un intento por adquirir dinámicamente un búfer nuevo. Si hay uno disponible, se acepta la TPDU; de otro modo, se descarta. Dado que el emisor está preparado para retransmitir las TPDU"s perdidas por la subred, no hay nada de malo en hacer que el receptor se deshaga de las TPDU"s, aunque se desperdicien algunos recursos. El emisor simplemente sigue intentando hasta que recibe una confirmación de recepción.

Si el servicio de red no es confiable, el emisor debe almacenar en búfer todas las TPDU"s enviadas, igual que en la capa de enlace de datos. Sin embargo, con un servicio de red confiable son posibles otros arreglos. En particular, si el emisor sabe que el receptor siempre tiene espacio de búfer, no necesita retener copias de las TPDU"s que envía. Sin embargo, si el receptor no puede garantizar que se aceptará cada TPDU que llegue, el emisor tendrá que usar búferes de todas maneras. En el último caso, el emisor no puede confiar en la confirmación de recepción de la capa de red porque esto sólo significa que ha llegado la TPDU, no que ha sido aceptada.

Aun si el receptor está de acuerdo en utilizar búferes, todavía queda la cuestión del tamaño de éstos. Si la mayoría de las TPDU"s tiene aproximadamente el mismo tamaño, es natural organizar los búferes como un grupo de búferes de tamaño idéntico, con una TPDU por búfer. Sin embargo, si hay una variación grande en el tamaño de las TPDU"s, de unos cuantos caracteres ingresados en una terminal hasta miles de caracteres provenientes de transferencias de archivos, el grupo de búferes de tamaño fijo presenta problemas. Si el tamaño de búfer se escoge igual a la TPDU más grande, se desperdiciará espacio cada vez que llegue una TPDU corta. Si el tamaño se escoge menor que el tamaño máximo de TPDU, se requerirán varios búferes para las TPDU"s grandes, con la complejidad inherente.

Otra forma de enfrentar el problema del tamaño de los búferes es el uso de búferes de tamaño variable. La ventaja aquí es un mejor uso de la memoria, al costo de una administración de búferes más complicada. Una tercera posibilidad es dedicar un solo búfer circular grande por conexión. Este sistema también hace buen uso de la memoria cuando todas las conexiones tienen una carga alta, pero es deficiente si algunas conexiones cuentan con poca carga.

El equilibrio óptimo entre el almacenamiento en búfer en el origen y en el destino depende del tipo de tráfico transportado por la conexión. Para un tráfico de bajo ancho de banda con ráfagas, como el producido por una terminal interactiva, es mejor no dedicarle búferes, sino adquirirlos de manera dinámica en ambos extremos. Dado que el emisor no puede estar seguro de que el receptor será capaz de adquirir un búfer, el emisor debe retener una copia de la TPDU hasta recibir su confirmación de recepción. Por otra parte, para la transferencia de archivos y otro tráfico de alto ancho de banda, es mejor si el receptor dedica una ventana completa de búferes, para permitir el flujo de datos a máxima velocidad. Por tanto, para un tráfico en ráfagas de bajo ancho de banda, es mejor mantener búferes en el emisor; para tráfico continuo de alto ancho de banda, es mejor hacerlo en el receptor.

A medida que se abren y cierran conexiones, y a medida que cambia el patrón del tráfico, el emisor y el receptor necesitan ajustar dinámicamente sus asignaciones de búferes. En consecuencia, el protocolo de transporte debe permitir que un host emisor solicite espacio en búfer en el otro extremo. Los búferes podrían repartiese por conexión o, en conjunto, para todas las conexiones en operación entre los dos hosts. Como alternativa, el receptor, sabiendo su capacidad de manejo de búferes (pero sin saber el tráfico generado) podría indicar al emisor "te he reservado X búferes". Si aumentara la cantidad de conexiones abiertas, podría ser necesario reducir una asignación, por lo que el protocolo debe contemplar esta posibilidad.

Una manera razonablemente general de manejar la asignación dinámica de búferes es desacoplarlos de las confirmaciones de recepción. Inicialmente, el emisor solicita una cierta cantidad de búferes, con base en sus necesidades percibidas. El receptor entonces otorga tantos búferes como puede. Cada vez que el emisor envía una TPDU, debe disminuir su asignación, deteniéndose por completo al llegar la asignación a cero. El receptor entonces incorpora tanto las confirmaciones de recepción como las asignaciones de búfer al tráfico de regreso.

Hasta ahora hemos supuesto tácitamente que el único límite impuesto a la tasa de datos del emisor es la cantidad de espacio de búfer disponible en el receptor. A medida que siga cayendo significativamente el precio de la memoria, podría llegar a ser factible equipar a los hosts con tanta memoria que la falta de búferes dejaría de ser un problema.

Si el espacio de búfer ya no limita el flujo máximo, aparecerá otro cuello de botella: la capacidad de carga de la subred. Si el emisor presiona demasiado, la subred se congestionará, pues será incapaz de entregar las TPDU"s a la velocidad con que llegan.

Lo que se necesita es un mecanismo basado en la capacidad de carga de la subred en lugar de la capacidad de almacenamiento en búfer del receptor. Es claro que el mecanismo de control de flujo debe aplicarse al emisor para evitar que estén pendientes demasiadas TPDU"s sin confirmación de recepción al mismo tiempo. Cualquier pequeña disminución en el desempeño de la red causará que se bloquee.

La capacidad de carga puede determinarse con sólo contar la cantidad de TPDU"s confirmadas durante algún periodo y dividirla entre el periodo. Durante la medición, el emisor debe enviar a la mayor velocidad posible, para asegurarse que sea la capacidad de carga de la red, y no la baja tasa de entrada, el factor limitante de la tasa de confirmaciones de recepción. El tiempo requerido para la confirmación de recepción de una TPDU transmitida puede medirse exactamente y mantenerse una media de operación. Dado que la capacidad de la red depende de la cantidad de tráfico en ella, debe ajustarse el tamaño con frecuencia para responder a los cambios en la capacidad de carga.

Multiplexión

La multiplexión de varias conversaciones en conexiones, circuitos virtuales y enlaces físicos desempeña un papel importante en diferentes capas de la arquitectura de la red. En la capa de transporte puede surgir la necesidad de multiplexión por varias razones. Por ejemplo, si en un host sólo se dispone de una dirección de red, todas las conexiones de transporte de esa máquina tendrán que utilizarla. Cuando llega una TDPU, se necesita algún mecanismo para saber a cuál proceso asignarla. Esta situación, es conocida como multiplexión hacia arriba.

Partes: 1, 2
Página siguiente