9         EL NIVEL DE TRANSPORTE EN INTERNET

 

Autor: Rogelio Montañana

Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-NoComercial-CompartirIgual 4.0 Internacional.

 

9       EL NIVEL DE TRANSPORTE EN INTERNET.. 9-1

9.1        INTRODUCCIÓN.. 9-1

9.1.1         Primitivas del servicio de transporte. 9-1

9.1.2         La interfaz sockets. 9-1

9.2        ELEMENTOS DE PROTOCOLOS DE TRANSPORTE.. 9-1

9.2.1         Establecimiento de una conexión. 9-1

9.2.2         Terminación de una conexión. 9-1

9.2.3         Control de flujo y de buffers. 9-1

9.2.4         Multiplexación. 9-1

9.2.5         Recuperación de caídas. 9-1

9.3        LOS PROTOCOLOS DE TRANSPORTE DE LA INTERNET: TCP Y UDP. 9-1

9.3.1         TCP (Transport Control Protocol) 9-1

9.3.2         La cabecera de segmento TCP. 9-1

9.3.3         Tamaño de segmento y fragmentación. 9-1

9.3.4         Flujo de datos en TCP. 9-1

9.3.5         Intercambio de información en TCP. 9-1

9.3.6         Gestión de conexión TCP. 9-1

9.3.7         Estados de TCP. 9-1

9.3.8         Conexiones medio abiertas y timer de keepalive. 9-1

9.3.9         Política de transmisión de TCP. 9-1

9.3.10      Problemas de paquetes pequeños. 9-1

9.3.10.1        Algoritmo de Nagle. 9-1

9.3.10.2        Síndrome de la ventana tonta y solución de Clark. 9-1

9.3.11      Control de congestión en TCP. 9-1

9.3.12      Gestión de timers en TCP. 9-1

9.3.13      Opciones del protocolo TCP. 9-1

9.3.14      UDP (User Datagram Protocol) 9-1

9.4        EJERCICIOS. 9-1

9.5        SOLUCIONES. 9-1

 


9.1      INTRODUCCIÓN

 

El nivel de transporte se encarga de suministrar el servicio de transporte de bits a las aplicaciones. Éstas funcionan generalmente según el paradigma cliente-servidor, por el cual una aplicación (cliente) toma la iniciativa y solicita los servicios a la otra (servidor).

 

Como ya sabemos la comunicación 'peer to peer' entre dos entidades del nivel de transporte ocurre en realidad gracias a los servicios ofrecidos por el nivel de red. Mientras que el nivel de red se ocupa de resolver los problemas propios de la topología de ésta (rutas y congestión fundamentalmente) el nivel de transporte sólo existe en las dos entidades extremas de la comunicación, por lo que también se le llama nivel host-host o extremo a extremo. El nivel de transporte no es consciente, ni debe serlo, de la manera como físicamente están interconectados los dos hosts, que puede ser por una LAN, una WAN o una combinación de múltiples redes de ambos tipos.

 

La unidad básica de intercambio de información a nivel de enlace se denomina trama (porque los datos van 'rodeados' de información de control por delante y por detrás). En el nivel de red esta unidad básica se conoce como paquete. No existe un término equivalente para la unidad de transferencia de información en el nivel de transporte; a falta de mejor alternativa utilizaremos para este fin el término OSI TPDU (Transport Protocol Data Unit); en la Internet se suele utilizar el término mensaje en el caso de UDP (servicio no orientado a conexión), y segmento en el de TCP (servicio orientado a conexión), pero esta nomenclatura no es compartida por otros protocolos de transporte.

 

Generalmente las aplicaciones requieren que el nivel de transporte les garantice la entrega de los datos al destinatario, sin errores, pérdidas ni datos duplicados; para que esto sea posible el nivel de transporte ofrecerá normalmente un servicio orientado a conexión, con retransmisiones en caso necesario. Este es el caso por ejemplo del protocolo TCP de Internet, utilizado en muchas aplicaciones como FTP (File Transfer Protocol, transferencia de ficheros), SMTP (Simple Mail Transfer Protocol, correo electrónico) , HTTP (HyperText Transfer Protocol, usado en tráfico Web), etc.

 

En ocasiones las aplicaciones se conforman -o incluso prefieren- un servicio menos fiable en el que los mensajes se envían sin pedir confirmación, de forma independiente unos de otros. Este tipo de servicio se suministra normalmente con un protocolo no orientado a conexión. El protocolo UDP de Internet es un ejemplo de este tipo de servicio. Entre los casos en que se quiere un servicio de este tipo se encuentran por ejemplo las aplicaciones en tiempo real ya que en ese caso no se quiere incurrir en el retardo propio de un protocolo orientado a conexión.

 

Al igual que en Internet en OSI también hay dos protocolos de transporte, uno orientado a conexión y uno no orientado a conexión. La tabla 5.1 muestra los más importantes protocolos de nivel de red y de transporte de Internet y sus corresponidentes protocolos OSI.

 

 

Tipo de protocolo

Internet

OSI

Nivel de red

IP (Internet Protocol)

CLNP (ConnectionLess Network Protocol)

Routing interno

OSPF (Open Shortest Path First)

IS-IS ( Intermediate System to Intermediate System)

Routing externo

BGP (Border Gateway Protocol)

IDRP (InterDomain Routing Protocol)

Nivel de transporte, orientado a conexión

TCP (Transmission Control Protocol)

TP4 (Transport Protocol clase 4)

Nivel de transporte, no orientado a conexión

UDP (User Datagram Protocol)

TP0 (Transport Protocol clase 0)

 

Tabla 5.1.- Correspondencia de protocolos Internet y OSI a nivel de red y de transporte

 

 

Normalmente las entidades del nivel de transporte se implementan como procesos en el sistema operativo del host, o bien procesos de usuario. El sistema operativo puede ser monousuario o multiusuario. En muchos casos el host tiene una sola instancia del nivel de red, y una sola del de transporte, pero muchas de los niveles superiores (aplicación o sesión); el nivel de transporte se encarga de mutiplexar el tráfico recibido de las diversas entidades de nivel superior en una única conexión a través del nivel de red.

 

Los protocolos de transporte no orientados a conexión, como UDP, son protocolos muy sencillos, que existen únicamente para permitir la correcta conexión de la capa de aplicación y la de red; actúan como una capa de adaptación bastante primitiva. Por esto la mayoría de nuestra discusión se centrará en los protocolos orientados a conexión, a los que nos referiremos implícitamente la mayor parte del tiempo.

 

9.1.1    Primitivas del servicio de transporte

 

En un servicio de transporte básico orientado a conexión (CONS) la secuencia de primitivas podría ser algo como lo siguiente:

 

 

 

 

9.1.2    La interfaz sockets

 

Como ya vimos en el tema 1 la interfaz utilizada entre los diferentes niveles de un mismo sistema no forma parte de un protocolo de comunicaciones. Dos sistemas necesitan acordar las reglas que seguirá la comunicación entre ellos en cada uno de los niveles, pero la forma como se realiza la comunicación vertical, es decir , la que ocurre dentro de un sistema es asunto interno que no incumbe a los protocolos. Esa comunicación vertical se realiza normalmente mediante las denominadas APIs (Application Programming Interfaces).

 

Aunque no requerida por las comunicaciones, la estandarización de las APIs comporta unos beneficios evidentes por la posibilidad de aprovechar software entre sistemas diferentes. Esto es especialmente cierto en el nivel de transporte, ya que es aquí donde interaccionarán más programas diferentes, correspondientes a las diversas aplicaciones que se desarrollen. Muchas implementaciones de TCP/IP disponen de una API para programación aplicaciones denominada sockets (literalmente enchufes, aunque nunca se utiliza esta denominación). Los sockets se introdujeron con el sistema operativo UNIX BSD (Berkeley Software Distribution) en 1982. La interfaz sockets es multiprotocolo, soporta TCP, UDP y otros protocolos.

 

Aun cuando no forman parte de ningún estándar oficial ni están recogidos en ningún RFC, los sockets son la API más extendida en programación de aplicaciones TCP/IP y forman un estándar 'de facto'. Existen implementaciones para muchos sistemas operativos no UNIX, e incluso en casos en que el sistema operativo no los incorpora suele haber una librería de rutinas sockets que permite adaptar programas con relativa facilidad. Por ejemplo, la interfaz WinSock permite adaptar aplicaciones MS Windows sobre diversas implementaciones de TCP/IP. Al no ser un estándar puede haber pequeñas diferencias entre implementaciones, por lo que es conveniente disponer siempre de la documentación correspondiente al software que se utiliza.

 

La filosofía básica de los sockets deriva directamente del sistema de entrada/salida de UNIX, con ampliaciones que permiten por ejemplo a un proceso servidor ponerse 'a la escucha'. Algunas de las rutinas generan y envían las TPDUs a partir de sus argumentos; éstas (las TPDUs) sí forman parte del protocolo, por lo que deben de ser conformes con el estándar correspondiente.

 

9.2      ELEMENTOS DE PROTOCOLOS DE TRANSPORTE

 

Al ocuparse de la comunicación extremo a extremo o punto a punto, el nivel de transporte se parece en algunos aspectos al nivel de enlace. Así por ejemplo, entre los asuntos de los que normalmente habrá de ocuparse se encuentran el control de errores (incluyendo mensajes perdidos o duplicados) y el control de flujo. Aunque las técnicas que se aplican son parecidas, existen importantes diferencias entre ambos motivadas por el hecho de que en el nivel de enlace hay sólo un hilo físico (o su equivalente) entre las dos entidades comunicantes, mientras que en el nivel de transporte hay toda una red. Las mayores diferencias entre el nivel de transporte y el de enlace son las siguientes:

 

o    El retardo que se observa en el nivel de transporte es normalmente mucho mayor y sobre todo más variable (mayor jitter) que en el de enlace.

 

o    En el nivel de enlace el medio físico entre las dos entidades tiene una capacidad de almacenamiento de información normalmente muy reducida y siempre la misma; en el de transporte los routers intermedios pueden tener una capacidad considerable y esta puede variar con el estado de la red.

 

o    En el nivel de enlace se asegura que las tramas llegarán al receptor en el mismo orden que han salido del emisor (salvo que se pierdan, en cuyo caso no llegarán); en el nivel de transporte esto es cierto solo cuando se utiliza un servicio orientado a conexión en el nivel de red; si se utiliza un servicio no orientado a conexión el receptor podría recibir los datos en orden distinto al de emisión.

 

o    En el nivel de enlace las dos entidades se 'ven' directamente (suponiendo una comunicación dúplex); a veces incluso de forma permanente, por ejemplo en una comunicación síncrona tipo HDLC están continuamente emitiendo la secuencia 01111110; esto permite que el emisor sepa en todo momento si el receptor está operativo, y el receptor sabe que los datos recibidos corresponden todos a una misma sesión del emisor. En el nivel de transporte la comunicación es indirecta; el emisor podría enviar datos, quedar fuera de servicio y más tarde entrar en funcionamiento otra vez; si no se adoptan las medidas oportunas el receptor podría recibir todos esos datos sin siquiera percatarse de que corresponden a dos sesiones distintas del emisor (incluso podrían pertenecer a dos usuarios distintos).

 

Recordemos que en el modelo OSI cada nivel presta sus servicios al nivel superior a través del SAP (Service Access Point), cada uno de los cuales es identificado por una dirección. Por ejemplo en Internet la dirección SAP por la que el nivel de red accede al servicio es la dirección IP del host, que hemos visto en el tema anterior. La dirección SAP por la que el nivel de transporte accede al servicio de red está formada por el campo protocolo del datagrama IP (6 para TCP y 17 para UDP, por ejemplo). A su vez el nivel de transporte ofrece sus servicios al nivel de aplicación a través de unos SAPs específicos, que en el caso de Internet son los denominados ports o puertos. Estos puertos se denominan también TSAPs (Transport Service Acces Point).

 

Para que un proceso cliente de un host pueda comunicar con un proceso servidor en otro host haciendo uso de los servicios de su nivel de transporte es preciso que conozca el TSAP correspondiente en el host de destino. Normalmente esta información forma parte del estándar del protocolo, por lo que es universalmente conocido y cualquier cliente que lo desee sabe que TSAP debe utilizar para acceder a dicho servidor. En cambio el TSAP del cliente no necesita ser conocido por otros usuarios y puede ser diferente para cada conexión.

 

9.2.1    Establecimiento de una conexión

 

En principio para establecer una conexión el cliente emite una TPDU de petición de conexión, y el servidor responde con una TPDU de aceptación; a partir de ese momento puede empezar el intercambio de datos. Sin embargo cuando analizamos el proceso de conexión con mayor detalle encontramos diversos problemas que pueden presentarse y que hay que prever.

 

Recordemos que en el nivel de transporte puede haber una gran fluctuación (a veces del orden de segundos) en el tiempo que tardan en llegar las TPDUs a su destino; las TPDUs pueden perderse o llegar duplicadas, ya que si el emisor no recibe confirmación reenviará la misma TPDU pasado el timeout. Imaginemos que el cliente intercambia una serie de TPDUs con el servidor, y cuando ya ha terminado la transacción cierra la sesión; segundos mas tarde de algún rincón de la red aparecen la misma secuencia de TPDUs del cliente duplicadas que llegan al servidor de nuevo; éste realizaría la misma transacción otra vez, con efectos posiblemente desastrosos[1].

 

Para evitar este tipo de problemas se utiliza para establecer la conexión el mecanismo conocido como saludo a tres vías (three-way handshake). La idea es que el servidor sólo aceptará la conexión después de haber pedido al cliente confirmación de que desea realizarla. En principio esto por sí solo no resuelve nuestro problema, ya que cabría pensar que después de la TPDU de petición inicial duplicada la red le entregue al servidor la TPDU de confirmación, también retrasada.

 

La solución a este problema es la siguiente: tanto el cliente como el servidor utilizan un protocolo de ventana deslizante para el envío de las TPDUs, para lo cual emplean un número de secuencia; a diferencia del número de secuencia que vimos en el nivel de enlace, el del nivel de transporte emplea rangos muy amplios (por ejemplo en TCP el número de secuencia se almacena en un campo de 32 bits, con lo que es un número módulo 232). Tanto el cliente como el servidor eligen de forma aleatoria o pseudoaleatoria el valor inicial del número de secuencia que van a utilizar, cada uno por separado para cada sentido de la comunicación. El cliente informa al servidor en su primera TPDU del número de secuencia elegido; por su parte el servidor le responde en otra TPDU con el número de secuencia elegido por él, incluyendo en ésta un ACK piggybacked de la TPDU recibida. De esta forma si el servidor recibe una TPDU de petición de conexión vieja responderá con una TPDU al cliente en la que pondrá en el campo ACK el número de secuencia recibido; cuando la respuesta llegue al cliente éste verá que ese número no corresponde con ninguna conexión que él tuviera pendiente de confirmación, por lo que rechazará la conexión; el servidor por su parte esperará recibir en el campo ACK de la siguiente TPDU un valor que corresponda con el que él ha enviado en la anterior.

 

La técnica de los números de secuencia aleatorios evita también el riesgo de que un proceso cliente que cae por algún motivo (por ejemplo por un fallo de corriente) utilice la misma conexión cuando reaparece más tarde, ya que normalmente el nuevo proceso intentará utilizar un número de secuencia diferente. Esta es una medida de seguridad ya que el nuevo proceso cliente podría pertenecer a otro usuario; supongamos por ejemplo que al inicio de la conexión se realiza una identificación con clave usuario/password ante el servidor, en tal caso el nuevo cliente podría acceder a todos los recursos del usuario anterior sin identificarse.

 

Generalmente se establece una vida máxima para las TPDUs en la red; de esta forma se reduce el riesgo de recibir duplicados retrasados. Cuando un sistema cae y vuelve a arrancar se recomienda esperar al menos el tiempo de vida de las TPDUs antes de activar el nivel de transporte; de esta manera es imposible que una TPDU de la sesión anterior pueda aparecer por alguna parte cuando se inicia la sesión nueva. En Internet por ejemplo el tiempo de vida máximo recomendado de las TPDUs es de 2 minutos, y se controla mediante el campo TTL en el datagrama IP.

 

Una vez establecidos los números de secuencia es posible utilizar para el intercambio de TPDUs cualquier protocolo de ventana deslizante. A diferencia del nivel de enlace, donde el protocolo se basa en numerar tramas, en el nivel de transporte se suelen numerar bytes, ya que el tamaño de las TPDUs puede ser muy variable. Para las retransmisiones se puede utilizar tanto retroceso n como repetición selectiva.

 

9.2.2    Terminación de una conexión

 

Una conexión puede terminarse de forma simétrica o asimétrica. La terminación asimétrica es unilateral, es decir uno de los dos hosts decide terminar y termina la conexión en ambos sentidos. En la terminación simétrica cada host corta la conexión únicamente en el sentido en el que emite datos; podemos considerar la terminación simétrica como dos circuitos simplex donde cada uno es controlado por el emisor.

 

La terminación asimétrica se considera anormal y puede provocar la pérdida de información, ya que cuando un host ha enviado la TPDU de desconexión ya no acepta más datos; entretanto el otro host podría haber enviado una TPDU de datos que no será aceptada.

 

En la terminación simétrica -la más normal- el host 1 'invita' al host 2 a desconectar mediante una TPDU DISCONNECT REQUEST; el host 2 responde con otra DISCONNECT REQUEST, a la cual el host 1 responde con una TPDU ACK y cierra la conexión; el host 2 cerrará la conexión al recibir el ACK. Por este mecanismo se asegura que no se pierden TPDUs 'en ruta' ya que ambos hosts tienen aviso previo de la desconexión y dan su conformidad explícitamente. Este mecanismo supone el intercambio de tres mensajes de forma análoga al proceso de conexión, por lo que también se denomina saludo a tres vías (aunque quizá debería llamarse ‘despedida a tres vías’); no existe forma fiable de terminar la conexión en menos mensajes sin correr el riesgo de perder datos.

 

Si se pierde alguna de las TPDUs de desconexión el mecanismo del saludo atres vías falla pues los hosts se quedan esperando eternamente la respuesta. Para evitar esto se utiliza un mecanismo de timeouts que resuelve el problema reenviando la TPDU perdida si se trata de un DISCONNECT REQUEST, o cerrando la conexión por timeout cuando lo que se ha perdido es el ACK. En el Tanenbaum Fig. 6-14 aparece una relación de los casos 'patológicos' que pueden ocurrir y como se resuelven.

 

Existen muchas circunstancias que pueden provocar que una conexión se quede medio abierta, es decir abierta sólo por un lado. Por ejemplo, un host puede quedar fuera de servicio sin previo aviso y el otro, que tenía una conexión abierta con él, quedar a la espera sin saber que ha ocurrido. Para resolver estas situaciones se prevé normalmente un tiempo máximo durante el cual una conexión puede estar abierta sin tráfico; pasado ese tiempo los hosts se envian mensajes de prueba (denominados keep-alive en TCP) para comprobar que el otro lado aún responde. Los valores de timeout para el envío de mensajes keep-alive son increíblemente grandes (la documentación de TCP sugiere 2 horas como valor por defecto). Un valor muy pequeño podría provocar que un fallo momentáneo en la red cerrara conexiones a nivel de transporte, perdiendo así la principal ventaja de las redes de datagramas.

 

Analicemos ahora que ocurre si dos hosts tienen establecida una conexión entre ellos y falla la red que los une. En el caso de utilizar un servicio orientado a conexión (X.25, ATM) generalmente la sesión termina de manera abrupta, pues la vía de comunicación (el circuito virtual) ha desaparecido y para restaurar la comunicación habrá que restablecer el circuito, presumiblemente por un camino físico diferente. En el caso de utilizar un servicio de red no orientado a conexión (IP, OSI CLNP) la red reencaminará los datagramas por una ruta alternativa (suponiendo que exista) por lo que lo único que el nivel de transporte detectará es la pérdida de unas pocas TPDUs, pero la conexión no se cortará.

 

9.2.3    Control de flujo y de buffers

 

El control de flujo en el nivel de transporte es fundamental, ya que la velocidad con que los datos llegan al receptor puede ser muy variable al intervenir multitud de factores.

 

Como ya hemos dicho se suelen utilizar protocolos de ventana desilzante. Mientras que en el nivel de enlace se asignaba de manera estática un espacio de buffers a cada conexión, en el nivel de transporte esta estrategia no es adecuada, pues el número de conexiones simultáneas puede variar muchísimo al no haber una interfaz física asociada a cada conexión.

 

Por este motivo la asignación de espacio para buffers en el nivel de transporte tiene dos características singulares que le diferencian del nivel de enlace. En primer lugar el espacio de buffers es común y compartido por todas las conexiones, entrantes y salientes. En segundo lugar el reparto del espacio entre las conexiones activas se hace de forma dinámica de acuerdo con las necesidades; una conexión con poco tráfico recibirá menos asignación que una con mucho tráfico. En todo momento cada conexión tiene asignado un espacio para emisión y uno para recepción; el espacio de emisión está ocupado con TPDUs pendientes de ser enviadas o de confirmación; el espacio de recepción tiene una parte ocupada con TPDUs recibidas pendientes de ser aceptadas por el nivel de aplicación, y otra libre reservada para TPDUs que puedan llegar del otro host.

 

Otra diferencia respecto al nivel de enlace estriba en que, mientras que el tamaño de las tramas suele ser constante para una conexión física dada, el tamaño de las TPDUs puede ser muy variable. Para optimizar la utilización del espacio se asignan segmentos de buffer de longitud variable. Para una máxima flexibilidad en este sentido tanto los números de secuencia como los tamaños de ventana cuentan generalmente bytes, no TPDUs.

 

La parte de buffer que el receptor tiene reservada para TPDUs que puedan llegarle es anunciada al emisor regularmente, para que éste sepa que cantidad de datos esta dispuesto a aceptar el receptor. Este espacio puede fluctuar mucho con el tiempo en función de la actividad que tenga esa y el resto de conexiones que mantenga el host.

 

Con este modo de funcionamiento el receptor realmente controla la situación, ya que si indica una ventana cero el emisor tendrá que esperar y no enviarle datos mientras el receptor no le anuncie una ventana mayor.

 

Veamos un ejemplo sencillo de como funcionaría una sesión TCP:

 

HOST 1                                                                 HOST 2

 

Seq=1000,Win=4000 ->

                                                                                <- Seq=1500,Ack=1001,Win=4000

Seq=1001,Ack=1501,datos(1000) ->

                                                                                <- Seq=1501,Ack=2001,datos(1000)

Seq=2001,Ack=2501,datos(1000) ->

Seq=3001,Ack=2501,datos(1000) ->

Seq=4001,Ack=2501,datos(1000) ->

bloqueado

                                                                                <- Seq=2501,Ack=5001,Win=0                      

…esperando…

                                                                                <- Seq=2501,Ack=5001,Win=2000

Seq=5001,Ack=2501,datos(1000) ->

                                                                                <- Seq=2501,Ack=6001,Win=3000

...

 

 

Supongamos ahora que en el ejemplo anterior se hubiera perdido la cuarta TPDU enviada de host1 a host2 (la que aparece en cursiva); en ese caso el host-2 no habría enviado el ACK 5001, y el host-1, al agotar el timeout correspondiente a esa TPDU la habría reenviado; funcionando con repetición selectiva la secuencia sería la siguiente:

 

HOST 1                                                                 HOST 2

 

Seq=1000,Win=4000 ->

                                                                                <- Seq=1500,Ack=1001,Win=4000

Seq=1001,Ack=1501,datos(1000) ->

                                                                                <- Seq=1501,Ack=2001,datos(1000)

Seq=2001,Ack=2501,datos(1000) ->

Seq=3001,Ack=2501,datos(1000) -> (perdida)

Seq=4001,Ack=2501,datos(1000) ->

                                                                                <- Seq=2501,Ack=3001

Seq=3001,Ack=2501,datos(1000) -> (reenviada por timeout)

bloqueado

                                                                               <-Seq=2501,Ack=5001,Win=0

…esperando…

                                                                                <-Seq=2501,Ack=5001,Win=2000

Seq=5001,Ack=2501,datos(1000) ->

                                                                                <-Seq=2501,Ack=6001,Win=3000

 

 

En caso de funcionar con retroceso n las cosas habrían sido ligeramente diferentes:

 

HOST 1                                                                 HOST 2

 

Seq=1000, Win=4000 ->

                                                                                <- Seq=1500,Ack=1001, Win=4000

Seq=1001, Ack=1501,datos(1000) ->

                                                                                <- Seq=1501,Ack=2001,datos(1000)

Seq=2001,Ack=2501,datos(1000) ->

Seq=3001,Ack=2501,datos(1000) -> (perdida)

Seq=4001,Ack=2501,datos(1000) -> (ignorada)

                                                                                <- Seq=2501,Ack=3001

Seq=3001,Ack=2501,datos(1000) -> (reenviada por timeout)

 

                                                                                <- Seq=2501,Ack=4001

Seq=4001,Ack=2501,datos(1000) -> (reenviada por timeout)

bloqueado

                                                                                <- Seq=2501,Ack=5001,Win=0

...esperando...

                                                                                <- Seq=2501,Ack=5001,Win=2000

Seq=5001,Ack=2501,datos(1000) ->

                                                                                <- Seq=2501,Ack=6001,Win=3000

 

En redes no orientadas a conexión los datagramas (y por tanto las TPDUs) pueden llegar desordenados, por lo que el nivel de transporte debe estar preparado para recibir números de secuencia desordenados (siempre y cuando se encuentren dentro del rango correspondiente a la ventana vigente en ese momento).

 

9.2.4    Multiplexación

 

En las redes públicas de conmutación de paquetes (X.25, frame relay y ATM), que son orientadas a conexión, el usuario paga por cada circuito virtual, lo cual estimula a utilizar el mínimo número de circuitos posible. Generalmente es el nivel de transporte el encargado en estos casos de multiplexar la diferentes conexiones solicitadas por el nivel de aplicación en una única conexión a nivel de red; dicho en terminología OSI el nivel de transporte presenta diferentes TSAPs sobre un único NSAP. Esto se conoce como multiplexación hacia arriba, ya que visto en el modelo de capas supone que varias direcciones del nivel de transporte confluyan en una única dirección del nivel de red.

 

También en redes no orientadas a conexión (IP o ISO CLNP) el nivel de transporte suele ocuparse de multiplexar el tráfico de las diferentes aplicaciones y usuarios (cada aplicación puede estar siendo utilizada por varios usuarios) en una única dirección a nivel de red.

 

Existen otras situaciones en las que interesa hacer multiplexación en sentido opuesto. Supongamos por ejemplo el caso de un servidor al que para mejorar su rendimiento se le han instalado dos interfaces de red, por ejemplo dos controladores Ethernet; supongamos que el servidor utiliza TCP/IP, y posee por tanto una dirección IP para cada interfaz. El servidor esta dedicado a una única aplicación, por lo que utiliza un único puerto. En este caso necesitamos hacer multiplexación hacia abajo. En ocasiones, debido a la forma como funcionan los protocolos o como se reparte la capacidad disponible, la multiplexación hacia abajo es interesante incluso cuando hay una sola interfaz física con la red; por ejemplo, si el protocolo a nivel de transporte no utiliza ventana deslizante sino parada y espera el crear varias conexiones a nivel de transporte para un mismo usuario del nivel de aplicación permite aprovechar los tiempos de espera que produce el protocolo. También sería útil la multiplexación si el algoritmo de reparto de recursos se basa en los usuarios del nivel de transporte; presentando varias conexiones obtendremos mejor rendimiento (seguramente con detrimento de los demás usuarios).

 

9.2.5    Recuperación de caídas

 

Ya hemos visto el  tipo de medidas preventivas que se adoptan para evitar que cuando una instancia del nivel de transporte en un host cae y se levanta mas tarde no sea posible recuperar la conexión previamente establecida, y haya que crear una nueva. Esto es una medida de seguridad fundamental para evitar inconsistencias en la información y accesos no autorizados.

 

Otro problema importante es que ocurre cuando cae todo un host, lo cual provoca la caída simultánea del nivel de transporte y el nivel de aplicación. Supongamos por ejemplo que un cliente está realizando una serie de actualizaciones en una base de datos, cada una de ellas contenida en una TPDU; a cada transacción el servidor responde con un ACK indicando que ha efectuado la operación correspondiente. En un determinado momento el servidor cae, rearrancando a continuación; podemos concluir que si el cliente ha recibido el ACK es que la actualización se ha efectuado, y si no no, pero como la actualización y el envío del ACK son sucesos consecutivos y no simultáneos siempre ocurrirá uno primero y el otro después; cualquiera que sea el orden elegido siempre podrá ocurrir que el host caiga entre ambos eventos, con lo que tendremos o bien una actualización efectuada y no notificada, o una notificación enviada al cliente de una actualización no realizada. Este tipo de problemas solo puede resolverse a nivel de aplicación mediante una posterior verificación de lo que realmente ha ocurrido.

 

9.3      LOS PROTOCOLOS DE TRANSPORTE DE LA INTERNET: TCP Y UDP

 

Como ya hemos comentado existen dos protocolos de transporte en la Internet: TCP es fiable, orientado a conexión con control de flujo, y UDP es no fiable (sin confirmación) no orientado a conexión y sin control de flujo. La TPDU de TCP se denomina segmento, y la de UDP mensaje o también datagrama UDP.

 

TCP prevé una comunicación full dúplex punto a punto entre dos hosts, no hay soporte para tráfico multicast. En UDP la comunicación es simplex (aunque obviamente un datagrama UDP puede ser respondido por el receptor con otro); en UDP es posible el tráfico multicast o broadcast.

 

El protocolo TCP es mucho más complejo que UDP.

 

9.3.1    TCP (Transport Control Protocol)

 

Recordemos que el nivel de transporte debe ofrecer algún mecanismo que permita distinguir a que aplicación van dirigidos los datos, lo que hemos denominado los TSAPs. En TCP los TSAPs se denominan ports o puertos.

 

En sentido estricto una conexión entre dos entidades usuarias del nivel de transporte queda identificada por los TSAPs en los que conectan cada una (podemos pensar en el TSAP como el conector telefónico, diríamos entonces que una conversación telefónica queda perfectamente especificada por los números de teléfono de las dos rosetas donde están enchufados los aparatos con los que se está hablando). Recordaremos que un TSAP en Internet está especificado por:

 

o    Dirección donde 'conecta' el nivel de red: dirección IP de los dos hosts

o    Dirección donde conecta el nivel de transporte (campo protocolo del datagrama IP): normalmente TCP ya que UDP al ser no orientado a conexión no puede establecer conexiones.

o    Dirección donde conecta el nivel de aplicación: esto es el puerto.

 

Dado que la conexión en el nivel de transporte siempre se suele realizar con el protocolo TCP este dato es innecesario y se suele omitir. Sin embargo en un mismo host un número de port puede ser utilizado simultáneamente por una aplicación para UDP y por otra para TCP; esto no plantea ningún conflicto ya que son TSAPs diferentes.

 

Así pues, una conexión de dos entidades usuarias del nivel de transporte se especifica por la combinación:

 

Dirección IP host 1 + port host 1 + dirección IP host 2 + port host 2

 

El port es un número entero entre 0 y 65535. Por convenio los números 0 a 1023 están reservados para el uso de servicios estándar, por lo que se les denomina puertos bien conocidos o well-known ports. Cualquier número por encima de 1023 está disponible para ser utilizado libremente por los usuarios. Los valores vigentes de los puertos bien conocidos se pueden consultar por ejemplo en el web de la IANA (Internet Assigned Number Authority) www.iana.org/numbers.html. En la tabla 5.2 se recogen algunos de los más habituales.

 

 

Puerto

Aplicación

Descripción

9

Discard

Descarta todos los datos recibidos (para pruebas)

19

Chargen

Intercambia cadenas de caracteres (para pruebas)

20

FTP-Data

Transferencia de datos FTP

21

FTP

Diálogo en transferencia de ficheros

23

TELNET

Logon remoto

25

SMTP

Correo electrónico

110

POP3

Servidor de correo

119

NNTP

News

 

Tabla 5.2.- Algunos ejemplos de puertos 'bien conocidos' de TCP

 

 

El Tanenbaum, como otros libros de texto, dice (pag. 523 y 526) que los puertos bien conocidos son los que están por debajo del 256; sin embargo el estándar establece que están reservados para este fin todos los valores por debajo de 1024.

 

Para comprender la relación entre los puertos y las conexiones en TCP veamos un ejemplo concreto: supongamos que cinco usuarios desde un host de dirección IP 134.123.1.2 inician una sesión de logon remoto (Telnet) hacia el host de dirección 221.198.34.21; cada uno de ellos ejecutará en su host un programa telnet cliente que abrirá una conexión con el servidor Telnet (puerto 23) en el otro; las conexiones establecidas podrían ser por ejemplo:

 

Usuario 1:             134.123.1.2.1024 con 221.198.34.21.23

Usuario 2:             134.123.1.2.1025 con 221.198.34.21.23

Usuario 3:             134.123.1.2.1026 con 221.198.34.21.23

Usuario 4:             134.123.1.2.1030 con 221.198.34.21.23

Usuario 5:             134.123.1.2.1031 con 221.198.34.21.23

 

Aquí hemos empleado la notación ‘dirección IP. Puerto’ para identificar el socket[2]; cada conexión queda identificada de forma no ambigua por los dos sockets que conecta. Obsérvese que la asignación de puertos para los clientes se hace por simple orden de llegada a partir del primer número de puerto no reservado. En el servidor todas las conexiones utilizan el puerto 23 (pues todas acceden al mismo proceso, el servidor telnet); en cambio en el cliente cada usuario es un proceso diferente y utiliza un puerto distinto.

 

Complicando un poco más el ejemplo anterior podríamos imaginar que el host cliente estuviera 'multihomed', es decir que tuviera dos interfaces físicas (por ejemplo dos tarjetas LAN) y por tanto tuviera dos direcciones IP; supongamos que los usuarios utilizan ambas interfaces alternativamente, en ese caso las conexiones podrían ser:

 

Usuario 1:             134.123.1.2.1024 con 221.198.34.21.23

Usuario 2:             134.123.1.3.1024 con 221.198.34.21.23

Usuario 3:             134.123.1.2.1025 con 221.198.34.21.23

Usuario 4:             134.123.1.3.1025 con 221.198.34.21.23

Usuario 5:             134.123.1.2.1030 con 221.198.34.21.23

 

Por otro lado el host cliente podría simultáneamente a las sesiones telnet enviar datagramas UDP al servidor. Aunque en este caso no se establece una conexión (pues se trata de un servicio CLNS) hay un puerto de origen y uno de destino; podría haber datagramas que tuvieran como puerto de origen el 1024 en el host 134.123.1.2 y como destino el 23 en 221.198.34.21; esto no causaría ninguna ambigüedad ya que el campo protocolo de la cabecera IP permitiría distinguir ambos tipos de paquetes entregando cada uno al servicio correspondiente del nivel de transporte en el host de destino.

 

9.3.2    La cabecera de segmento TCP

 

La cabecera de un segmento TCP tiene la estructura que se muestra en la tabla 5.3.

 

 

Campo

Longitud (bits)

Puerto origen

16

Puerto destino

16

Número de secuencia

32

Número de ACK

32

Longitud de cabecera TCP

4

Reservado

4

CWR (Congestion Window Reduced)

1

ECE (ECN Echo)

1

URG (Urgent)

1

ACK (Acknowledgement)

1

PSH (Push)

1

RST (Reset)

1

SYN (Synchronize)

1

FIN (Finish)

1

Tamaño de ventana

16

Checksum

16

Puntero de datos urgentes

16

Opciones

0, 32, 64, …

Datos

0-523960 (65495 bytes)

 

Tabla 5.3.- Estructura de la cabecera de un segmento TCP

 

 

Puerto origen y puerto destino: identifican los puertos que se van a utilizar en cada host para comunicar con las aplicaciones que intercambian datos.

 

Número de secuencia: indica el número de secuencia que corresponde en la conexión al primer byte que se envía en el campo datos de ese segmento.

 

Número de ACK: indica el número de secuencia del primer byte del próximo segmento que se espera recibir del otro lado.

 

Longitud de cabecera TCP: especifica la longitud en palabras de 32 bits, excluido el campo datos (el campo opciones hace que dicha longitud pueda variar).

 

A continuación hay 4 bits no utilizados, seguidos por ocho flags indicadores de un bit de longitud cada uno:

 

o    CWR: Congestion Window Reduced. Tiene que ver con el control de congestión de IP que no describiremos aquí

 

o    ECE: ECN Echo (ECN=Explicit Congestion Notification). Tiene que ver con el control de congestión de IP que no describiremos aquí.

 

o    URG (urgent): sirve para indicar que el segmento contiene datos urgentes; en ese caso el campo puntero de datos urgentes contiene la dirección donde terminan éstos.

 

o    ACK (acknowledgement): indica que en este segmento el campo Número de ACK tiene el significado habitual (número del próximo byte que se espera recibir), de lo contrario carece de significado. En la práctica el bit ACK esta a 1 siempre, excepto en el primer segmento enviado por el host que inicia la conexión.

 

o    PSH (push): indica que el segmento contiene datos PUSHed. Esto significa que deben ser enviados rápidamente a la aplicación correspondiente, sin esperar a acumular varios segmentos.

 

o    RST (reset): se usa para indicar que se debe abortar una conexión porque se ha detectado un error de cualquier tipo; por ejemplo una terminación unilateral de una conexión o que se ha recibido un segmento con un valor inadecuado del número de secuencia o número de ACK, posiblemente producido por un duplicado retrasado de un intento de conexión.

 

o    SYN (synchronize): este bit indica que se está estableciendo la conexión y está puesto sólo en el primer segmento enviado por cada uno de los dos hosts en el inicio de la conexión.

 

o    FIN (finish): indica que no se tienen más datos que enviar y que se quiere cerrar la conexión. Para que una conexión se cierre de manera normal cada host ha de enviar un segmento con el bit FIN puesto.

 

Tamaño de ventana: indica la cantidad de bytes que se está dispuesto a aceptar del otro lado en cada momento. Se supone que se garantiza una cantidad suficiente de espacio en buffers. Mediante este parámetro el receptor establece un control de flujo sobre el caudal de datos que puede enviar el emisor.

 

Checksum: sirve para detectar errores en el segmento recibido; estos podrían ser debidos a errores de transmisión no detectados, a fallos en los equipos (por ejemplo en los routers) o a problemas en el software (por ejemplo reensamblado incorrecto de fragmentos). Recordemos que el datagrama IP contenía un checksum, pero aquel solo comprendía la información de cabecera y además ese checksum desaparece en IPv6. El algoritmo utilizado en TCP es el mismo que el de IP: sumar todos los campos de 16 bits usando aritmética de complemento a 1 y calcular el complemento a 1 del resultado, pero en este caso el checksum se hace sobre todo el segmento, incluidos los datos, no sólo sobre la información de cabecera. Para el cálculo del checksum se antepone al segmento una pseudocabecera que incluye la dirección IP de origen y destino, el protocolo de transporte utilizado (TCP en este caso) y la longitud del segmento. La pseudocabecera (así denominada porque sólo se utiliza en el cálculo, pero no forma parte del segmento) permite a TCP comprobar que no ha habido errores en la transmisión a nivel IP (detectar por ejemplo cuando un segmento ha sido entregado al host equivocado).

 

Puntero de datos urgentes: indica el final de éstos, ya que el segmento podría contener datos no urgentes. TCP no marca el principio de los datos urgentes, es responsabilidad de la aplicación averiguarlo.

 

El campo opciones habilita un mecanismo por el cual es posible incluir extensiones al protocolo. Entre las más interesantes se encuentran las siguientes:

 

o    Tamaño máximo de segmento

 

o    Uso de repetición selectiva (en vez de retroceso n)

 

o    Uso de NAK (acuse de recibo negativo en caso de no recepción de un segmento)

 

o    Uso de ventana mayor de 64 Kbytes mediante el empleo de un factor de escala

 

De las opciones hablaremos más adelante.

 

9.3.3    Tamaño de segmento y fragmentación

 

TCP divide (o agrupa) los mensajes recibidos del nivel de aplicación en TPDUs denominadas segmentos; en el momento de establecer la conexión cada host informa al otro del máximo tamaño de segmento que está dispuesto a aceptar; este tamaño deberá ser como mínimo de 536 bytes, correspondiente normalmente a un datagrama IP de 576 bytes menos 20 bytes de cabecera IP y 20 de cabecera TCP (la longitud de segmento se refiere a la parte de datos de TCP).

 

Un segmento TCP siempre se transporta en un datagrama IP. Cuando la red ha de fragmentar en algún punto un datagrama IP el datagrama sigue fragmentado el resto del viaje hasta el host de destino; una vez allí el nivel de red se ocupa de juntar todos los fragmentos en su buffer y reconstruir el datagrama original, del cual extrae entonces el segmento original y lo pasa a TCP; si uno de los fragmentos se pierde el nivel de red del receptor será incapaz de reconstruir el datagrama original, y por tanto descartará, una vez expirado el TTL, todos los fragmentos recibidos y no pasará ninguna parte de ese segmento al nivel de transporte; TCP agotará el timer, detectará el segmento faltante y pedirá retransmisión al emisor. Por tanto cuando un fragmento de un datagrama se pierde todos los fragmentos se retransmiten nuevamente; el proceso se repite hasta que todos los fragmentos consiguen llegar correctamente al receptor. También puede suceder que la fragmentación se produzca ya en el host emisor del segmento, en cuyo caso realizará fragmentado todo el trayecto.

 

El Tanenbaum tercera edición dice (pag. 525):

 

Un segmento que es demasiado grande para una red por la que debe transitar puede ser dividido en múltiples segmentos por un router. Cada nuevo segmento obtiene su propia cabecera TCP e IP, con lo que la fragmentación por routers aumenta el overhead total (porque cada segmento adicional añade 40 bytes de información de cabecera extra).

 

El párrafo anterior contiene varios errores que es preciso aclarar. En primer lugar los routers no analizan ni procesan segmentos, sino paquetes o datagramas; por tanto tampoco fragmentan segmentos, sino paquetes; cada paquete-fragmento recibe una cabecera IP propia, pero no una nueva cabecera TCP; mas aun, el nivel de red ni siquiera analiza al fragmentar un paquete si lo que contiene es un segmento TCP, un datagrama UDP o cualquier otra cosa (podría ser un mensaje ICMP, por ejemplo). Por tanto el overhead añadido por la fragmentación no es de 40 bytes por fragmento (20 de la cabecera IP y 20 de la TCP), sino de 20 (mas el correspondiente a la información de control de las tramas adicionales que se produzcan a nivel de enlace). El nivel de transporte no se ve en absoluto involucrado en el proceso de fragmentación y reensamblado de los paquetes, que sólo afecta al nivel de red en el router (o host) que realiza la fragmentación y en el host al que va destinado el datagrama, que es el que efectúa el reensamblado. Afortunadamente el párrafo erróneo ha sido suprimido en la cuarta edición del libro (pág. 536).

 

En ocasiones el host emisor emplea la técnica de descubrimiento de la MTU del trayecto o ‘Path MTU discovery’ (MTU=Maximum Transfer Unit) para averiguar el tamaño de datagrama máximo que puede utilizar, con lo que puede generar en origen los datagramas de tamaño apropiado evitando así la fragmentación en ruta. Para ello el host emisor envía un datagrama del tamaño máximo que pretende utilizar con el bit DF (Don't Fragment) puesto; si el datagrama llega a su destino deducirá que todo el trayecto soporta esa MTU; en caso contrario el host emisor recibirá un mensaje ICMP Destination Unreachable generado por el router donde se produzca el rechazo. En muchas implementaciones el mensaje ICMP de rechazo vendrá acompañado de una indicación del tamaño de MTU máximo que se habría tolerado en esa red, para facilitar así al host emisor la labor de tanteo.  Cuando esto no ocurra el host emisor tendrá que deducir ese tamaño máximo a partir de una búsqueda binaria, hasta dar con el tamaño adecuado y reintentará con un datagrama más pequeño, hasta conseguir que llegue. En IPv6 la técnica de ‘Path MTU discovery’ es obligatoria, ya que la fragmentación en ruta no está permitida.

 

9.3.4    Flujo de datos en TCP

 

Los segmentos, al viajar en datagramas IP, pueden perderse, llegar desordenados o duplicados. Es responsabilidad de TCP resolver todos estos problemas y generar un flujo de bits fiable para el nivel de aplicación. Cada segmento es acomodado el solo en un datagrama, si bien luego puede tener que ser fragmentado para su envío, como hemos visto en el apartado anterior. Nunca se combinan en un segmento datos pertenecientes a dos conexiones TCP diferentes.

 

Las aplicaciones que comunican haciendo uso de los servicios que ofrece TCP no tienen conciencia de la existencia de segmentos o datagramas. Desde su punto de vista el servicio de transporte que ofrece TCP es de un flujo continuo de bits (stream), como si hubiera un hilo físico que las comunicara. Si la aplicación emisora desea que la información sea transmitida a la aplicación receptora en mensajes discretos deberá incluir los delimitadores adecuados, ya que no hay ninguna garantía de que TCP genere un segmento por cada escritura que la aplicación efectúe en su buffer. TCP puede tomarse la libertad de agrupar varias escrituras de la aplicación en su buffer en un mismo segmento, o trocear una escritura en varios dependiendo del tamaño de ésta, del MSS elegido y de las circunstancias. Por ejemplo el TCP emisor podría decidir retener varios mensajes recibidos de la aplicación si éstos son muy pequeños para agruparlos y crear segmentos mayores usando así la red de manera más eficiente.

 

Para poder enviar datos prioritarios y responder ante situaciones urgentes existen dos mecanismos extraordinarios por los que las aplicaciones pueden indicar a TCP su deseo de enviar rápidamente datos al otro extremo.

 

Uno de ellos es el denominado indicador PUSH. Cuando una aplicación desea que los datos entregados a TCP salgan enseguida, sin esperar más datos de la aplicación, lo indica poniendo a 1 el indicador PUSH; este indicador se utiliza por ejemplo cuando en una transferencia FTP se envía el último segmento, o cuando en una sesión telnet el usuario pulsa la tecla return[3]; en estos casos si no se utilizara PUSH se correría el riesgo de que TCP se quedara esperando mas datos de la aplicación para construir un segmento mayor.

 

El otro mecanismo de envío rápido de datos se denomina datos urgentes, y como su nombre indica es aún más expeditivo que el anterior. Por ejemplo en una sesión telnet se utiliza este procedimiento para enviar los caracteres DEL, CTRL-C, o cuando se pulsa la tecla BREAK o ATTN. En estos casos no solo se desea enviar cuanto antes los caracteres recién tecleados, sino que se quiere que estos pasen por delante de cualesquiera otros que hubiera pendientes de enviar a la aplicación y se le entreguen a ésta sin esperar a que los solicite (por ejemplo para abortar una ejecución en marcha cuando ésta no espera leer datos).

 

La existencia de datos ‘Pushed’ y de datos urgentes se indica mediante los correspondientes bits indicadores o ‘flags’ en la cabecera TCP. En el caso de datos urgentes se indica además el punto en el segmento donde terminan éstos; es responsabilidad de la aplicación averiguar en que punto del segmento empiezan los datos urgentes.

 

9.3.5    Intercambio de información en TCP

 

El intercambio de segmentos en TCP se desarrolla de acuerdo con un protocolo de ventana deslizante con un número de secuencia de 32 bits. El número de secuencia cuenta bytes transmitidos, por lo que la secuencia se reinicia cada 4 GB (equivalentes a 4,3 minutos en una línea SDH de 155 Mb/s, suponiendo que toda la capacidad útil de la línea se utilizara para esa conexión TCP).

 

TCP utiliza ACK piggybacked, por lo que en la cabecera de cada segmento hay previstos dos campos de 32 bits, uno para el número de secuencia y otro para el número de ACK. El campo número de secuencia indica el número del primer byte transmitido dentro de ese segmento. El campo ACK indica el número del primer byte que se espera recibir en el siguiente segmento (o sea se sigue el estilo del campo 'next' en HDLC). En la práctica el ACK piggybacked raramente se aprovecha ya que la mayoría de las aplicaciones generan tráfico muy asimétrico; normalmente uno de los dos TCP se ve oligado a enviar muchos segmentos vacíos con el único fin de informar al emisor que los datos han sido recibidos.

 

El mecanismo normal de funcionamiento de TCP es retroceso n, aunque también puede utilizarse repetición selectiva si las dos entidades participantes lo soportan y lo negocian al iniciar la conexión.

 

Cada segmento enviado incluye un tamaño de ventana en el que el receptor anuncia la cantidad de datos que está dispuesto a recibir. De esta forma el receptor puede ejercer control de flujo sobre el emisor. El tamaño de ventana es un campo de 16 bits, por lo que el valor máximo es de 64 Kbytes.

 

9.3.6    Gestión de conexión TCP

 

El mecanismo utilizado en TCP para establecer una conexión es el de saludo a tres vías. Un proceso normal sería el siguiente:

 

 

 

 

En el primer segmento el host 1 indica al host 2 que desea establecer una conexión (bit SYN puesto) y le informa del número de secuencia que ha elegido (x); el host 2 le responde con otro segmento en el que acepta la conexión (bit SYN puesto) y le indica el número de secuencia que él ha elegido para las transmisiones en el sentido contrario (y); además le acusa recibo de su número de secuencia al indicarle en el ACK que el próximo byte que espera recibir de él es x + 1. Host 1 responde con un tercer mensaje en el que acusa recibo del número de secuencia de host 2.

 

En este ejemplo hemos supuesto el caso más simple de establecimiento de una conexión. El Host 1 podría incluír ya en esos primeros segmentos datos dirigidos a la aplicación; esto está permitido siempre y cuando los datos sean retenidos por el TCP receptor hasta que la aplicación correspondiente decida si acepta la conexión.

 

Una vez establecida la conexión puede empezar el intercambio de información; cada lado puede enviar datos al otro de forma independiente, sin necesidad de que el otro le corresponda con más datos. Normalmente si fluyen datos en ambos sentidos los ACK irán incluidos (‘piggybacked’) en los segmentos de vuelta, pero si el tráfico discurre predominantemente en un sentido (como es lo normal) se producirán segmentos vacíos con el único fin de acusar recibo de los envíos. Los valores de SEQ y ACK se van incrementando a medida que progresa la transmisión. Los valores de ventana anunciados por cada host permiten al otro conocer la disponibilidad que tiene de recibir datos.

 

El número de secuencia inicial es elegido por cada host de forma pseudoaleatoria. El RFC 793, que describe el estándar TCP, recomiendan utilizar para esto un contador que se incremente en una unidad cada 4ms, aproximadamente; esto se puede conseguir fácilmente basándose en algún reloj del sistema. Con este algoritmo el número de secuencia se da la vuelta cada 4 horas 46 minutos, aproximadamente. Esta forma de elegir el número de secuencia inicial reduce la probabilidad de que si uno de los dos hosts cae y rearranca pueda coincidir el número de secuencia nuevo con el viejo, lo cual podría producir que se tomaran como válidos segmentos duplicados retrasados, o que el TCP del otro lado continuara dialogando con el nuevo proceso como si fuera el viejo. Para aumentar aún más la seguridad el estándar recomienda que se garantice una separación mínima en el timepo de 2 minutos desde que cae un TCP hasta que se levanta el nuevo, para asegurar de esa forma que no pueden aparecer en el TCP de destino duplicados retrasados que puedan mezclarse en la nueva conexión (2 minutos es un valor máximo bastante normal del parámetro TTL o tiempo de vida, que fija el tiempo máximo que un datagrama puede estar pululando por la red antes de desaparecer).

 

Para comprender hasta que punto es importante la no coincidencia de números de secuencia entre sesiones imaginemos la siguiente situación: dos usuarios X e Y mantienen ambos una conexión telnet desde la máquina 167.172.23.43 a la máquina 144.38.76.3; en un primer momento sus conexiones son:

 

Usuario X:             167.172.23.43.1024 con 144.38.76.3.23

Usuario Y              167.172.23.43.1025 con 144.38.76.3.23

 

1024 y 1025 son los puertos utilizados por los procesos clientes telnet en 167.172.23.43 y 23 es el puerto utilizado por el proceso servidor telnet en 144.38.76.3.

 

Supongamos ahora que el host 167.172.23.43 (cliente) cae y se levanta a continuación, y que los dos usuarios reanudan sus respectivas sesiones telnet (que han quedado medio abiertas en el servidor) pero ahora se conecta Y antes que X. Las conexiones antiguas han desaparecido, y dado que los puertos se asignan por orden de llegada ahora se asignarían en orden inverso:

 

Usuario X:             167.172.23.43.1025 con 144.38.76.3.23

Usuario Y              167.172.23.43.1024 con 144.38.76.3.23

 

En condiciones normales los clientes telnet intentarán abrir nuevas conexiones, con lo que el servidor cerrará las antiguas. Pero si de alguna forma los clientes telnet entraran en las conexiones viejas del servidor  sin cerrarlas cada usuario entraría directamente en la sesión del otro sin necesidad de identificarse con la contraseña correspondiente, lo cual evidentemente no es aceptable. La utilización de números de secuencia grandes y aleatorios suministra un cierto nivel de seguridad ante estas situaciones.

 

Para terminar una conexión TCP se utiliza normalmente el procedimiento simétrico del saludo a tres vías, en el cual cada lado cierra su parte de forma independiente como si se tratara de una conexión simplex. El intercambio de mensajes típico es el siguiente:

 

 

 

 

9.3.7    Estados de TCP

 

El software (o proceso) TCP de un host puede mantener en un momento dado múltiples conexiones simultáneas con homólogos suyos en otros hosts. Para cada una de esas conexiones TCP conserva en todo momento información del estado en que se encuentra (por ejemplo conexión establecida, pendiente de establecer o no conexión).

 

La secuencia de estados que se suceden en el establecimiento de una conexión TCP en un servidor aparece en la tabla 5.4, mientras que la tabla 5.5 nos muestra la secuencia equivalente en el caso de un cliente.

 

 

Estado del servidor

Evento

Descripción

CLOSED

 

Estado (ficticio) en que se encuentra una conexión antes de existir

 

La aplicación en el servidor hace una apertura pasiva

 

LISTEN

 

El servidor espera una conexión del cliente

 

El TCP del servidor recibe un SYN, devuelve un SYN/ACK

 

SYN-RECEIVED

 

El servidor espera un ACK

 

El TCP del servidor recibe un ACK

 

ESTABLISHED

 

El ACK ha sido recibido y la conexión se ha establecido

 

Tabla 5.4.- Secuencia de estados que ocurren en el establecimiento de una conexión TCP en un servidor

 

 

Estado del cliente

Evento

Descripción

CLOSED

 

Estado (ficticio) en que se encuentra una conexión antes de existir

 

La aplicación cliente solicita una conexión. El TCP del cliente envía un SYN

 

SYN-SENT

 

El TCP cliente ha enviado un SYN al servidor

 

El TCP cliente recibe SYN/ACK y envía ACK

 

ESTABLISHED

 

La transferencia de datos puede comenzar

 

Tabla 5.5.- Secuencia de estados que ocurren en el establecimiento de una conexión TCP en un cliente

 

 

Una vez en el estado ESTABLISHED ambos TCP permanecerán así hasta que se inicie el procedimiento de cierre de la conexión. En condiciones normales cualquiera de los dos procesos puede iniciar la desconexión enviando un segmento con el bit FIN puesto; la secuencia de estados en el TCP que inicia la desconexión es la que se muestra en la tabla 5.6, mientras que la tabla 5.7 muestra la secuencia de estados en el TCP que es ‘invitado’ a cerrar la conexión.

 

 

Estado del TCP que cierra la conexión

Evento

Descripción

ESTABLISHED

La aplicación local solicita cerrar

 

 

TCP envía FIN/ACK

 

FIN-WAIT-1

 

El TCP local está esperando respuesta del otro lado. En este punto aún pueden llegar datos válidos.

 

TCP recibe un ACK

 

FIN-WAIT-2

 

El TCP local ha recibido un ACK del otro lado, pero no un FIN. Se siguen aceptando los datos que pudieran llegar del otro lado

 

TCP recibe FIN/ACK. Envía ACK

 

TIME-WAIT

 

La conexión se mantiene en el limbo ante la posibilidad de recibir aun datos duplicados o un FIN duplicado. El tiempo de espera es igual al doble del tiempo de vida de un segmento

CLOSED

 

Se borra toda la información relativa a esta conexión.

 

Tabla 5.6.- Secuencia de estados que ocurren en el cierre de una conexión TCP en el host que inicia la desconexión

 

 

Estado del TCP 'invitado' a cerrar

Evento

Descripción

ESTABLISHED

TCP recibe FIN/ACK

 

CLOSE-WAIT

 

Ha llegado un FIN

 

TCP envía un ACK

 

 

 

TCP espera a que su aplicación cierre la conexión. La aplicación podría aún enviar más datos

 

La aplicación local cierra la conexión

 

 

TCP envía FIN/ACK

 

LAST-ACK

 

TCP Está esperando el ACK final

 

TCP recibe un ACK

 

CLOSED

 

Se borra toda la información sobre la conexión

 

Tabla 5.7.- Secuencia de estados que ocurren en el cierre de una conexión TCP en el host que es invitado a terminar la conexión

 

 

Los nombres utilizados en estas tablas corresponden con los empleados en el RFC 793, y en muchas implementaciones de TCP. El comando netstat -an, que permite examinar el estado de las conexiones existentes en un host UNIX, utiliza esta misma nomenclatura.

 

9.3.8    Conexiones medio abiertas y timer de keepalive

 

En principio el estándar TCP no establece el requerimiento de que una conexión TCP tenga un tráfico mínimo para permanecer establecida. Cabría pensar en la posibilidad de que una conexión TCP estuviera abierta durante días sin transmitir ni un solo segmento, y en principio no habría razón para terminarla. En la práctica esto supone que si en una conexión desaparece uno de los dos TCP el otro podría quedar eternamente esperando dándose lo que se denomina una conexión medio abierta. Si todo funcionara como es debido las conexiones medio abiertas nunca deberían ocurrir, puesto que cada TCP debería cerrar ordenadamente sus conexiones. Pero a veces los procesos TCP terminan de forma abrupta, no dando tiempo al cierre ordenado de sus conexiones; esto es especialmente común en tiempos recientes a partir de la proliferación de los ordenadores personales conectados directamente a Internet en los que el usuario con frecuencia no termina los procesos de la forma correcta, o desconecta de la red su ordenador dejando las conexiones medio abiertas en el otro lado.

 

Esas conexiones medio abiertas consumen recursos inútilmente, por lo que es conveniente establecer algún mecanismo por el cual un TCP pueda ‘sondear’ periódicamente sus conexiones para comprobar que el otro lado aún está operativo; si el TCP de una conexión deja de responder durante un número determinado de mensajes de sondeo se considera que esa conexión está medio abierta y se procede a cerrarla de la forma mas civilizada posible, liberando así los recursos que está utilizando.

 

Los mensajes de sondeo son lo que se conoce como mensajes ‘keep-alive’ y la periodicidad con la que se producen viene fijada por el parámetro denominado timer de keepalive. Los mensajes de keepalive fueron añadidos a posteriori al TCP, y se implementan de una forma muy sencilla: el TCP envía un segmento que repite el último byte enviado; el TCP receptor no pasará este byte a la aplicación, pero debe generar un segmento de ACK; con esto el emisor ya sabe que su interlocutor está operativo.

 

Los keepalive se suelen implementar en servidores, que son los que mas sufren el problema de las conexiones medio abiertas. Por la forma como se implementan los mensajes de keepalive funcionan aun cuando el TCP remoto no implemente keepalive, ya que se emplea una característica que forma parte del funcionamiento estándar de TCP. El mecansimo de keepalive no debe ser tan estricto que una pérdida momentánea de coenctividad produzca el cierre de una conexión TCP, ya que en una red como Internet es fundamental permitir que las cosas funcionen aun cuando haya fallos momentáneos en el nivel de red, que sabemos que no es fiable. El timer de keepalive puede tener valores en torno a los dos minutos; los tiempos recomendados para cortar una conexión TCP inactiva pueden llegar a ser de hasta dos horas.

 

9.3.9    Política de transmisión de TCP

 

Como ya hemos comentado, el receptor en una transmisión TCP anuncia regularmente el tamaño de ventana que tiene disponible para que el emisor sepa cuantos datos más puede enviarle. Cuando un receptor tiene lleno su buffer anuncia una ventana de 0 bytes, con lo que el emisor queda bloqueado hasta nueva orden.

 

Existen dos circunstancias en las que con ventana cero (ventana cerrada) el emisor puede enviar datos. Una es cuando se presentan datos urgentes; estos siempre deben ser aceptados por el receptor, ya que se supone que no pueden esperar. La otra excepción es que el emisor puede siempre enviar un segmento de un byte de datos, para forzar al receptor a devolver un ACK y así comprobar cual es la situación; esto evita situaciones de bloqueo que de otro modo podrían producirse por la pérdida de segmentos ACK en la red. La periodicidad con la que el emisor ‘tantea’ al receptor con segmentos de un byte para comprobar que su ventana sigue cerrada se fija con el parámetro conocido como timer de persistencia.

 

Salvo por lo requerido en el bit PUSH o en datos urgentes, los emisores TCP pueden organizarse los envíos como mejor les convenga. TCP podría por ejemplo decidir agrupar la información que recibe de la aplicación para enviar segmentos mas grandes y así reducir el overhead de proceso y de cabeceras que supone el envío de segmentos pequeños. Incluso el uso del bit PUSH no garantiza la inmediata expedición de un segmento, en situaciones de veradera congestión el TCP puede decidir ignorar el bit Push y agrupar varios mensajes de la aplicación en el mismo segmento.

 

9.3.10             Problemas de paquetes pequeños

 

9.3.10.1   Algoritmo de Nagle

 

Un caso extremo de baja eficiencia se produce cuando la aplicación en el lado del emisor genera un byte de datos cada vez; imaginemos por ejemplo lo que ocurre cuando se efectúa una conexión telnet mediante una emulación de terminal ANSI (VT100 o similar); muchos programas, como por ejemplo el editor vi de UNIX, necesitan para funcionar correctamente que el host remoto procese cada carácter que se teclea, por lo que es preciso utilizar el modo de eco remoto mediante el cual el host remoto se encarga de representar en pantalla cada carácter que se teclea. En estas condiciones por cada tecla pulsada la aplicación envía a TCP los caracteres uno a uno; en principio TCP debería enviar cada carácter en un segmento conteniendo 20 bytes de cabecera al cual el nivel de red añadiría 20 de la cabecera IP; ese segmento TCP recibe a continuación su correspondiente segmento vacío (es decir sin datos) con el ACK del anterior. Como la representación en pantalla en el host local se realiza a través del host remoto instantes más tarde la aplicación del sistema remoto (el servidor telnet) responde con el eco del carácter pulsado, que es de nuevo un datagrama IP de 41 bytes, a lo cual el host cliente responde con otro datagrama IP de 40 bytes que contiene otro segmento ACK vacío; en total se transfieren 162 bytes para dos caracteres transmitidos, lo cual da una eficiencia del 1,2% (2/162) (y aquí no hemos considerado la información de control del nivel de enlace, tramas Ethernet por ejemplo, que añadiría aún más overhead).

 

Para evitar estas situaciones la mayoría de las implementaciones de TCP fijan un timeout de 500 mseg antes de enviar un ACK vacío; si en ese tiempo se genera algún tráfico de vuelta el ACK puede viajar ‘piggybacked’ en él; por ejemplo en nuestro caso salvo que el host estuviera muy cargado la aplicación telnet respondería antes de 500 mseg y el ACK podría viajar en el mismo segmento que lleva el carácter de vuelta; de esta forma la eficiencia mejora ya que se suprime un ACK; la eficiencia sería entonces del 1,6 % (2/122).

 

Para mejorar aún más la eficiencia en estas situaciones se utiliza lo que se conoce como el algoritmo de Nagle. La idea es muy simple: cuando el tráfico de la aplicación llega al TCP en bytes uno por uno se envía el primero en un segmento y se retienen los demás hasta recibir el ACK correspondiente al byte enviado; una vez recibido el ACK se envía un segmento con todos los bytes que hubiera pendientes y se empieza a acumular de nuevo hasta recibir el siguiente ACK. También se envía un segmento si el número de caracteres acumulados en el buffer es igual a la mitad de la ventana, o al máximo tamaño del segmento.

 

En cierto modo el algoritmo de Nagle sustituye el protocolo de ventana deslizante por un mecanismo de parada y espera.

 

El algoritmo de Nagle es autoadaptativo, ya que en una red muy cargada los ACK tardarán más en llegar, con lo que automáticamente los segmentos que se envíen serán mayores y el overhead disminuirá; el usuario observará una latencia mayor en la red, pero esto es un mal menor cuando se trata de reducir la congestión en la red. Cuando la red esté descargada y responde muy rápido cada carácter tecleado viaja en un segmento independiente , y será respondido con otro que contendrá el carácter de eco, sin más retardo que el tiempo que tarde el host en responder.

 

El algoritmo de Nagle se puede aplicar a datos ‘Pushed’ pero no a datos urgentes, y se debe inhibir cuando se desea transferir información en tiempo real; por ejemplo la posición del ratón en una sesión X-Windows debe ser transmitida inmediatamente ya que de lo contrario el movimiento en pantalla resulta errático (como es bien sabido el uso de terminales X es poco eficiente y requiere gran cantidad de recursos).

 

9.3.10.2   Síndrome de la ventana tonta y solución de Clark

 

Imaginemos ahora la situación inversa; en vez de enviar los datos byte a byte es la aplicación en el TCP receptor la que recoge los bytes de uno en uno. La situación que se daría sería la siguiente:

 

1.       El TCP emisor envía datos sin parar al TCP receptor

2.       El buffer del TCP receptor se llena

3.       El TCP receptor notifica al emisor que su ventana está cerrada (ventana 0)

4.       El TCP emisor deja de enviar datos

5.       La aplicación receptora lee 1 byte del buffer de TCP

6.       El TCP receptor envía un ACK al emisor para anunciarle que dispone de 1 byte de espacio

7.       El TCP emisor envía un segmento con 1 byte de información útil

8.       Volvemos al punto 2.

 

El bucle se repite hasta terminar la sesión. Se están generando como antes segmentos con un byte de información útil, pero esta vez el causante es el receptor que los recoge en pequeñas dosis. Este comportamiento se conoce como síndrome de la ventana tonta.

 

La solución a esto, propuesta por Clark en el RFC 813, consiste en que el TCP del receptor no debe notificar el cambio de ventana al emisor entretanto no tenga una cantidad razonable de espacio libre en su buffer; por razonable se entiende cualquiera de las dos condciones siguientes: el espacio suficiente para aceptar un segmento de la longitud máxima admitida en esa conexión, o la mitad del espacio total del buffer.

 

El algoritmo de Nagle y la solución de Clark son dos mecanismos complementarios que intentan resolver un mismo problema: el causado por la transmisión innecesaria de segmentos pequeños.

 

9.3.11             Control de congestión en TCP

 

Como ya hemos explicado el TCP receptor puede controlar el flujo de datos que recibe del emisor anunciando un valor adecuado del tamaño de ventana. Si el receptor anuncia un tamaño de ventana 0 (lo que se conoce como 'cerrar la ventana') el emisor dejará de transmitir hasta nueva orden (salvo por las dos excepciones ya mencionadas, datos urgentes y segmentos con un byte).

 

Sin embargo la falta de espacio de buffer en el receptor es solo una de las causas por las que el emisor puede verse obligado a bajar el ritmo de emisión; la otra es la presencia de congestión en la red. Para aclarar la diferencia entre estos dos importantes conceptos imaginemos el siguiente experimento:

 

o    Un supercomputador establece una conexión TCP con un ordenador personal poco potente a través de una conexión directa  ATM OC3 (155,52 Mb/s) ‘back to back’. El circuito se establece mediante la categoría de servicio UBR. Al transferir datos se mide un rendimiento máximo de 50 Mb/s; analizando la situación se observa que el ordenador personal tiene su buffer lleno prácticamente todo el tiempo, por lo que su TCP está continuamente cerrando su ventana; evidentemente el subsistema de entrada/salida del ordenador personal no es capaz de absorber los datos al ritmo que los envía el supercomputador.

 

o    En una segunda prueba se repite la misma transferencia entre ambos ordenadores, pero en vez de un enlace directo se conectan a través de una red ATM pública (utilizando también un servicio UBR). En este caso el rendimiento de la transferencia en horas punta es de solo 10 Mb/s, aun cuando se observa que el TCP del ordenador personal tiene espacio de sobra en sus buffers de entrada.

 

La diferencia estriba en que en el primer caso está actuando como factor limitante el control de flujo en el receptor y en el segundo la congestión en la red. Presumiblemente la red pública no es capaz en horas punta de dedicar a esa conexión los recursos necesarios para transmitir los 50 Mb/s que puede absorber el ordenador personal. Basta que uno solo de los enlaces del trayecto se vea afectado de congestión para limitar el tráfico en todo el trayecto, y por tanto el rendimiento de la comunicación entre los hosts.

 

Imaginemos por un momento que pasaría si TCP no incluyera ningún mecanismo de control (mejor dicho de autocontrol) en situaciones de congestión; dado que el receptor anuncia buffers disponibles el emisor inyectará paquetes en la red al ritmo que se lo permita su conexión física; cuando los paquetes lleguen a la parte congestionada de la red, no pudiendo aceptar todo el tráfico entrante, los routers empezarán a acumularlos en sus buffers y cuando estos se llenen los descartarán; en el lado del TCP receptor se recibirán solo una parte de los segmentos, por lo que o bien se devolverán segmentos NAK al emisor, o bien sencillamente no se enviarán los ACKs y se esperará que el emisor reenvíe por timeout; en cualquier caso el emisor tiene que reenviar datos. Los segmentos descartados en ruta son inútiles y cargan innecesariamente las líneas por las que pasan; este tráfico inútil podría propagar la congestión a zonas de la red que en principio no la sufrían, aumentando así la magnitud del problema y disminuyendo aún mas el rendimiento en toda la red. Este efecto de 'bola de nieve' se denomina colapso de congestión ('congestion collapse') y puede llegar a dejar toda una red completamente fuera de servicio.

 

Evidentemente TCP no puede ser ajeno a las situaciones de congestión en la red, pero como notificamos al emisor que hay saturación en algún punto del trayecto y que debe bajar el ritmo con que envía datos? TCP no emplea mecanismos explícitos para notificar la congestión. El mecanismo que emplea es indirecto y se basa en la pérdida de datagramas por la red. Esto se basa en una premisa fundamental: el medio físico se considera altamente fiable por lo que siempre que el TCP emisor detecte que los segmentos no han sido recibidos en su destino (al no recibir los correspondientes ACKs) deducirá que la red está descartando paquetes por congestión y bajará el ritmo de sus envíos. Dado que el control de congestión de TCP se basa en la fiabilidad del medio físico cuando esta condición no se cumple (radioenlaces móviles, por ejemplo) es preciso realizar modificaciones a los algoritmos normales de TCP o incorporar en el nivel de enlace mecanismos de comprobación o corrección de errores que suministren esa fiabilidad, ya que de lo contrario TCP interpreta como congestión los problemas debidos al medio físico y si en estas condiciones se baja el ritmo el rendimiento decrece aún más.

 

Para autoregularse el TCP emisor maneja una ventana de congestión que le indica que cantidad de datos puede inyectar en la red en un momento dado. Dicha ventana actúa simultáneamente y en paralelo a la ventana que anuncia el receptor indicando los buffers disponibles, que podríamos denominar ventana de control de flujo. En cada momento el emisor tomará en consideración la mas pequeña de las dos ventanas, para asegurarse de que no satura al receptor y que tampoco provoca, o contribuye a agravar, una situación de congestión en la red.

 

Mientras que la ventana de control de flujo es notificada al emisor por el receptor, la ventana de congestión es calculada por el emisor a partir de la cantidad de retransmisiones que tiene que realizar; cuando ve que no se produce ninguna retransmisión va aumentando paulatinamente la ventana, hasta llegar al punto donde falla algún segmento (es decir, agota el timer y se retransmite), momento en el cual la reduce (suponiendo que la ventana de control de flujo no imponga ninguna limitación). Generalmente la ventana crece de froma lenta y gradual, mientras que la reducción se lleva a cabo de manera drástica. Los algoritmos de crecimiento y disminución de la ventana de congestión en TCP son siempre autoadaptativos y forman una parte fundamental del rendimiento del protocolo; estos algoritmos han sido y son objeto de detallados estudios y experimentaciones, por lo que son altamente sofisticados y funcionan bien en situaciones muy diversas.

 

Inicialmente la ventana de congestión se fija a un valor igual al del máximo tamaño de segmento negociado en el momento de establecer la conexión (que depende a su vez del MTU); supongamos por ejemplo que dicho tamaño es de 1 Kbyte y que todos lols segmentos que se van a generar tendrán este tamaño. Inicialmente TCP envía un segmento de 1 KByte e inicia un timer; si se recibe el ACK antes de expirar el timer significa que el segmento ha llegado a su destino correctamente, por lo que la ventana de congestión se amplía a 2 KBytes; a continuación se envían 2 segmentos, y se inicia el timer (en realidad 2 timers, uno por segmento); por cada segmento confirmado dentro del intervalo previsto se amplía la ventana en un segmento (1 KByte), por lo que, suponiendo que no se pierda ninguno, en el ciclo siguiente la ventana pasará de 2 a 4 KBytes; en condiciones normales esto supone que la ventana crece exponencialmente, ya que se duplica en cada envío; esta técnica se denomina slow-start, aunque no es precisamente lenta, sino todo lo contrario; por ejemplo empezando en 1 KByte en sólo 7 iteraciones llegaría a 64 Kbytes, valor máximo permitido por el tamaño de ventana de TCP. En condiciones normales (sin congestión) el slow-start provoca que la ventana de congestión crezca rápidamente, con lo que pronto supera a la ventana de control de flujo, momento a partir del cual prevalece ésta y la ventana de congestión deja de crecer.

 

Pero que ocurre cuando se detecta la pérdida de un segmento, es decir, hay congestión en la red? Supongamos en nuestro ejemplo que hemos ido duplicando el tamaño de la ventana de congestión hasta llegar a 32 KBytes, momento en el cual la red pierde un datagrama IP, es decir expira un timeout. Cuando ocurre esto el slow-start entra en una nueva fase. De entrada la ventana de congestión se reduce, y lo hace de una manera drástica, al valor inicial de un segmento (1 KByte en nuestro ejemplo). Además se establece un 'umbral de peligro' en un valor igual a la mitad del tamaño que tenía la ventana cuando se produjo la retransmisión (en nuestro ejemplo el umbral de peligro sería 16 KBytes) Ahora la ventana de congestión empieza a crecer como antes, pero sólo hasta el umbral de peligro; a partir de ahí la ventana se incrementa de forma mucho más lenta en sólo un segmento cada vez (un proceso que podríamos llamar 'very-slow-start'); cada vez que se produce una retransmisión se recalcula el umbral de peligro como la mitad de la ventana vigente en ese momento, y se empieza una nueva fase. El proceso se repite indefinidamente mientras dure la transmisión.

 

Supongamos que la ventana de control de flujo del receptor es siempre mayor que la de congestión (y por tanto no se ejerce control de flujo) y que la pérdida de paquetes se presenta siempre justo cuando la ventana de congestión supera los 20 KBytes; supongamos también que todos los segmentos que se transmiten son de 1 Kbyte; la evolución de la ventana de congestión sería entonces la siguiente:

 

 

Fase

Umbral de peligro (en Kbytes)

Tamaños sucesivos de la ventana (en Kbytes)

Primera

64 (valor por defecto)

1,2,4,8,16,32

Segunda

16

1,2,4,8,16,17,18,19,20,21

Tercera

10,5

1,2,4,8,10,11,12,13,14,15,16,17,18,19,20,21

 

 

A partir de la tercera fase el proceso se repite indefinidamente. Cabría pensar que el mecanismo no se estabiliza nunca, y en efecto así es; aun en el caso de que fijáramos la ventana de congestión en el valor de 20 KBytes tampoco se estabilizaría, ya que en la práctica el tamaño de la ventana de congestión cambia continuamente. En última instancia la única forma que tiene el emisor de ajustar la ventana de congestión al límite de sus posibilidades es tanteando y fallando de vez en cuando. Se podría argumentar que no es preciso retroceder en tan gran medida en caso de fallo, pero recordemos que cuando se produce congestión en una red es mejor pasarse de precavido, pues de lo contrario el problema se puede hacer inmanejable.

 

9.3.12             Gestión de timers en TCP

 

Hasta ahora hemos supuesto que TCP era capaz de detectar los segmentos perdidos fijando un valor adecuado para el timer de retransmisión; en realidad para estar completamente seguros de que no va a llegar el segmento ACK habría que esperar dos veces el valor del TTL, lo cual en prácticamente todos los casos es excesivo. Para el timer se suele elegir un tiempo por encima del cual la probabilidad de recibir el ACK sea muy pequeña. La elección de un valor adecuado para este timer tiene una consecuencia directa en el funcionamiento eficiente de TCP; si el timer es demasiado alto el emisor esperará innecesariamente en muchos casos por ACKs que nunca llegarán, y si es demasiado bajo se producirán reenvíos innecesarios de segmentos que habían sido correctamente recibidos.

 

La elección de valores de timer adecuados es mucho más compleja en el nivel de transporte que en el nivel de enlace. Además de las fluctuaciones naturales debidas a las diferencias en capacidad y retardo de unas conexiones a otras, el nivel de transporte ha de hacer frente a oscilaciones debidas a la presencia de elementos intermedios (routers y enlaces) y de situaciones de congestión que están fuera de su control; aun en ausencia de congestión los routers pueden tener largas colas de paquetes que atender, los enlaces pueden ser de diversas velocidades, y la ruta puede variar durante la conexión.

 

Por todo esto los valores del timer de retransmisión en el nivel de transporte se establecen mediante algoritmos autoadaptativos que dinámicamente ajustan los valores al estado de la red, según es percibido éste por el nivel de transporte en el host emisor.

 

El algoritmo utilizado en TCP para el cálculo de los timers fue diseñado por Van Jacobson, que es también el autor de la técnica slow-start que hemos visto antes. En realidad la gestión de los timers es una parte del slow-start necesaria para un efectivo control de la congestión en TCP.

 

Para estimar el timer de retransmisión TCP mide lo que tardan en llegar los ACK de los segmentos enviados; se supone que estos tiempos son una buena estimación del tiempo de ida y vuelta o RTT (Round Trip Time) de los segmentos, en base al cual ha de calcularse el valor del timer de retransmisión. El valor medio del RTT (que denominaremos MRTT) se estima mediante la fórmula iterativa siguiente:

 

                MRTTn = a MRTTn-1 + (1-a) RTTn                                                                                                                            (10.1)

 

donde RTTn es el tiempo de ida y vuelta medido para el último (n-ésimo) ACK recibido. El parámetro a permite ajustar el peso o la importancia que se quiere dar al último valor frente a los anteriores; con un a pequeño se consigue que los valores anteriores tengan poca relevancia, adaptándose así a situaciones cambiantes con rapidez. Con a grande se reacciona con más inercia a los cambios. En TCP a vale normalmente 7/8. Lo que calcula esta fórmula es pues una media aritmética ponderada de los valores de RTT, dándoles un peso inversamente proporcional a su antigüedad (cuanto más viejo menos importante).

 

Obtener una buena estimación del valor medio de RTT resuelve sólo una parte del problema; sabemos que los valores de RTT se distribuirán alrededor del valor medio, pero cual es el valor adecuado del timer de retransmisión, o sea, ¿cual es el valor umbral a partir del cual podemos considerar que el ACK no llegará?. Las primeras implementaciones de TCP utilizaban 2*MRTT como valor del timer, pero eso tenía el inconveniente de que cuando los valores de RTT fluctuaban mucho el umbral de 2*MRTT resultaba demasiado bajo y se producían excesivas retransmisiones innecesarias; en cambio cuando la dispersión era pequeña 2*MRTT daba un valor excesivo ya que en la mayoría de los casos no había que esperar tanto para dar por perdido un segmento. Para tener una estimación más precisa del timeout necesitamos saber además del valor medio el grado de dispersión, o dicho de otro modo conocer la anchura de la campana de distribución de los valores, lo que en estadística se conoce como la desviación estándar. Para estimar esta magnitud de manera sencilla se utiliza la siguiente fórmula:

 

                Dn = b Dn-1 + (1-b) ½MRTTn-1 – RTTn½                                                                                            (10.2)

 

Como antes b es un factor que permite regular la inercia a los cambios (a mayor b mayor inercia); normalmente suele valer 3/4[4]. De forma parecida al cálculo de MRTT el valor actual es una media ponderada del valor instantáneo y de los valores anteriores, con un peso decreciente en función de la antigüedad.

 

Una vez obtenidos MRTT y D podemos calcular el timeout de retransmisión. Para esto se utiliza generalmente la fórmula siguiente:

 

                Timeout de retransmisión = MRTT + 4 * D                                                                                   (10.3)

 

El cálculo del RTT de los segmentos reenviados plantea un problema. No es posible saber con seguridad si el ACK se debe al primer o al segundo envío y una interpretación errónea podría alterar de manera importante el valor de MRTT. La solución a este problema, conocida como algoritmo de Karn, consiste sencillamente en ignorar a efectos del cálculo del MRTT (y de D) los ACK de los segmentos que son retransmitidos. Sin embargo esto plantea otro problema: podría ocurrir que el RTT aumentara de forma repentina (por ejemplo por un cambio en la ruta de los datagramas) hasta el punto que superara el timeout; a partir de ese momento todos los segmentos serían retransmitidos, con lo que los valores de MRTT y D (y por tanto el timeout de retransmisión) se mantendrían constantes, puesto que los ACK recibidos serían ignorados; estas múltiples retransmisiones provocarían una notable pérdida de eficiencia. Para evitarlo el algoritmo de Karn prevé que cada vez que se produzca una retransmisión el timeout de retransmisión se duplique; de esta forma si por alguna razón el RTT aumenta de forma repentina el timer de retransmisión crece rápidamente evitando así que se produzcan muchas retransmisiones; una vez el TCP emisor vuelve a recibir ACKs de segmentos no retransmitidos vuelve a calcular el tiemout de retransmisión a partir de los nuevos valores de MRTT y D de acuerdo con la fórmula 10.3. Esta técnica, denominada retroceso exponencial del timer, tiene el interesante efecto colateral de reducir el tráfico en situaciones de congestión.

 

9.3.13             Opciones del protocolo TCP

 

El protocolo TCP está en evolución permanente; las mejoras se experimentan en prototipos y luego se documentan en RFCs, convirtiéndose en extensiones opcionales al protocolo básico. Las extensiones son generalmente compatibles entre sí y se van incorporando paulatinamente en muchas implementaciones de TCP. Cuando dos TCPs conectan negocian entre ellos la relación de extensiones que cada uno quiere utilizar, y emplean solo aquellas que están soportadas por ambos. Veamos algunas de esas extensiones.

 

El máximo tamaño de ventana estándar de TCP es de 64 KBytes - 1. El tamaño de ventana establece la máxima cantidad de datos que pueden estar pendientes de confirmación en una comunicación. Cuando la comunicación utiliza un canal de elevada capacidad o gran latencia (es decir elevado valor de RTT) es posible que el emisor tenga que esperar a recibir confirmación antes de seguir enviando; por ejemplo en una comunicación vía satélite es normal tener valores de RTT de 500 mseg; si un host transmite datos a otro mediante TCP por un enlace vía satélite de 2 Mb/s no podrá enviar más de 64 Kbytes cada 500 mseg, ya que una vez ha llenado la ventana tiene que esperar a recibir el ACK; pero 64 Kbytes cada 500 mseg equivale a 64 * 1024 * 8 / 0,5 = 524.288 / 0,5 = 1,049 Mb/s, por lo que el enlace solo podrá aprovecharse al 50% aproximadamente. En general el rendimiento de una conexión siempre vendrá limitado por la fórmula:

 

                Capacidad máxima = Tamaño de ventana / RTT

 

Es decir, siempre que el producto capacidad*RTT de una conexión sea superior al tamaño de ventana el rendimiento vendrá limitado por ésta ya que la conexión no es capaz de 'llenar la tubería' de datos y se producirán tiempos de espera en la comunicación. Cuando se diseñó TCP era impensable tener este tipo de problemas, que aparecieron inicialmente con la disponibilidad de enlaces vía satélite de alta velocidad (2 Mb/s). Hoy en día la posibilidad de tener enlaces de alta velocidad en redes de área extensa plantea otras situaciones en las que también se da este problema, por ejemplo una comunicación TCP sobre una línea ATM OC3 de 155,52 Mb/s con un RTT de 8 ms puede obtener con la ventana estándar un ancho de banda máximo de 524.288 / 0,008 =  65,5 Mb/s; para aprovechar completamente la línea sería precisa una ventana mínima de 155.520.000 * 0,008 = 1.244.160 bits = 152 Kbytes[5]. El RFC 1323, incorporado en muchas implementaciones de TCP, resuelve este problema ya que permite utilizar un factor de escala para ampliar el tamaño de ventana hasta 230 (1 GByte).

 

Otro campo en el que TCP ha sido mejorado es el tipo de actuación en caso de errores. Las primeras implementaciones utilizaban retroceso n, con lo que cuando se perdían segmentos el rendimiento caía de forma apreciable. El RFC 1106, incorporado en muchas implementaciones, prevé el funcionamiento con repetición selectiva, de manera que el emisor sólo tiene que reenviar el segmento o segmentos que han llegado erróneos.

 

RFC 1106 también propone un mecanismo de envío de acuses de recibo negativos (NAK) cada vez que se recibe un segmento sin haber recibido el anterior. Sin embargo el RFC 1106 también toma en cuenta que al ser transportados en datagramas los segmentos pueden no llegar en orden, por lo que la no recepción de un segmento en el momento esperado no quiere decir necesariamente que éste se haya perdido; lo que hace el emisor en estos casos es esperar a que el receptor insista, por ejemplo si le comunica que ha recibido los tres segmentos siguientes a uno dado y sigue faltando éste es bastante probable que se haya perdido, con lo que lo reenvía sin esperar a agotar el timeout. Evidentemente este mecanismo solo se aplicará si la retransmisión no ha sido provocada antes por agotamiento del timer de retransmisión.

 

9.3.14             UDP (User Datagram Protocol)

 

TCP tiene la robustez y funcionalidades propias de un protocolo de transporte orientado a conexión; sin embargo esa robustez y funcionalidad conllevan una cierta complejidad; por ejemplo cualquier transmisión de información TCP requiere como mínimo el intercambio de seis mensajes para establecer la comunicación y terminarla; además mientras una conexión existe ocupa una serie de recursos en el host. A veces no se requiere toda esa funcionalidad; en esos casos se prefiere que el nivel de transporte preste un servicio más sencillo, no orientado a conexión y no fiable (por no fiable queremos decir que el receptor no acusa recibo de las TPDUs enviadas). Algunos ejemplos de situaciones en las que es más conveniente un servicio no orientado a conexión son las siguientes:

 

o    El tipo de aplicación no requiere una fiabilidad total y no puede tolerar el retardo producido por los ACKs y las retransmisiones de TCP; este es el caso por ejemplo en la transmisión de vídeo o audio en tiempo real.

 

o    La aplicación por su propia naturaleza requiere el envío de uno o dos mensajes únicamente; ejemplos de estas aplicacioens son las siguientes: sincronización de relojes (NTP), consultas al servidor de nombres (DNS), mensajes de gestión de la red (SNMP), etc.; en el DNS no se considera necesario un transporte fiable porque si se pierde el datagrama la aplicación lo reenviará; en el caso de NTP o SNMP la pérdida de un datagrama no es importante porque la información se está actualizando a intervalos regulares (por ejemplo cada 5 minutos).

 

o    Se desea hacer envíos multidestino (multicast o broadcast); esto sólo es posible con un protocolo no orientado a conexión, ya que por su propia naturaleza los protocolos orientados a conexión son punto a punto (en TCP no es posible establecer conexiones multipunto).

 

El protocolo no orientado a conexión de Internet se conoce como UDP (User Datagrama Protocol); su nombre ya da una idea de la naturaleza no fiable del servicio de transporte ofrecido. Entre las aplicaciones que utilizan UDP se encuentran TFTP (Trivial File Transfer Protocol), DNS (Domain Name Server), SNMP (Simple Network Management Protocol), NTP (Network Time Protocol) y NFS (Network File System)[6], etc.

 

Las TPDUs intercambiadas por UDP se denominan mensajes o datagramas UDP. Recordemos que los mensajes UDP se identifican por el valor 17 en el campo protocolo del datagrama IP.

 

Una característica interesante de UDP es que puede ser utilizado por aplicaciones que necesitan soporte de tráfico multicast o broadcast. Con TCP esto no es posible debido a la naturaleza punto a punto, orientada a conexión del protocolo.

 

UDP no suministra ningún mecanismo de control de flujo o control de congestión. Cuando lo que se envía es únicamente un mensaje (por ejemplo una consulta al DNS) esto es innecesario, ya que presumiblemente un mensaje aislado no creará problemas de congestión y será siempre aceptado en destino (y de no ser así el mismo problema habría surgido con TCP para el inicio de la conexión). Si se va a enviar un flujo de mensajes, por ejemplo vídeo o audio en tiempo real, se deberán tomar las medidas adecuadas para asegurar la capacidad suficiente en la red (mediante mecanismos de reserva de capacidad, por ejemplo) y evitar la congestión no excediendo lo solicitado en el momento de hacer la reserva; afortunadamente en estos casos se suele conocer a priori con bastante aproximación el tráfico que se va a introducir en la red.

 

En caso de congestión en la red parte de los datagramas serán descartados por la red sin informar por ningún mecanismo al emisor, ni al receptor. En caso de saturación del receptor este sencillamente ignorará los datagramas que no pueda aceptar. En algunos se contemplan a nivel de aplicación mecanismos de control que permiten al receptor detectar si se producen pérdidas (por ejemplo numerando los datagramas) informando al emisor para que baje el ritmo de emisión si se rebasa un umbral determinado.

 

De forma similar a los segmentos TCP, los mensajes UDP se dirigen a la aplicación adecuada mediante el puerto de destino, especificado en la cabecera. Análogamente a TCP los puertos UDP se identifican mediante un campo de 16 bits (números entre 0 y 65535). Aun en el caso de coincidir en número con un puerto TCP son TSAPs diferentes, como ya hemos comentado antes. Al igual que en TCP los valores por debajo de 1024 están reservados para los puertos denominados 'bien conocidos' (well-known ports), aunque su significado es diferente en la mayoría de los casos, pues también lo son los servicios. La tabla 5.8 muestra algunos de los puertos UDP más utilizados.

 

 

Servicio

Puerto

Descripción

Echo

7

Devuelve el datagrama al emisor

Discard

9

Descarta el datagrama

Daytime

13

Devuelve la hora del día

Quote

17

Devuelve una 'frase del día'

Chargen

19

Generador de caracteres

Nameserver

53

Servidor de nombres de dominios

Bootps

67

Puerto servidor utilizado para cargar información de configuración Bootp

Bootpc

68

Puerto cliente utilizado para recibir información de configuración

TFTP

69

Trivial File Transfer Protocol

SunRPC

111

Sun Remote Procedure Call

NTP

123

Network Time Protocol

SNMP

161

Usado para recibir consultas de gestión de la red

SNMP-trap

162

Usado para recibir avisos de problemas en la red

 

Tabla 5.8.- Algunos de los puertos UDP más utilizados

 

La estructura de un mensaje UDP se muestra en la tabla 5.9.

 

 

Campo

Longitud (bits)

Puerto origen

16

Puerto destino

16

Longitud

16

Checksum

16

Datos

0-524056 (65507 bytes)

 

Tabla 5.9.- Estructura de un mensaje UDP

 

 

A contnuación describimos el significado de cada uno de los campos de la cabecera UDP:

 

 

 

 

 

 

De la misma forma que un host o un router pueden tener que fragmentar un datagrama que contenga un segmento TCP, es posible que el host emisor o algún router intermedio tengan que fragmentar un mensaje UDP porque sea mayor que la MTU permitida en la red por la que ha de enviarse. Análogamente a los segmentos TCP la fragmentación ocurre de froma transparente a UDP y la cabecera del mensaje solo aparecerá en el primer fragmento; en cambio cada framento deberá incluir una nueva cabecera IP.

 

El funcionamiento del protocolo UDP está descrito en el RFC 768.

 

9.4      EJERCICIOS

 

 

1.       Indique si es verdadera o falsa cada una de las siguientes afirmaciones:

 

a)       La fragmentación en Internet es siempre competencia del nivel de red, es decir del protocolo IP.

 

b)       Siempre que se establece una comunicación TCP entre dos hosts en una red local se ejecuta previamente el protocolo ARP.

 

c)       El nivel de transporte siempre ha de asegurar un envío fiable de los datos, ya que en algunos protocolos (p. ej. IP) el nivel de red no lo garantiza.

 

d)       En TCP no es posible enviar un segmento sin haber recibido el ACK del anterior.

 

e)       El bit PSH (datos Pushed) puede utilizarse en TCP para forzar el envío de datos en segmentos independientes.

 

f)        En TCP el checksum se comprueba siempre; en caso de discrepancia entre el valor calculado y el recibido el segmento es descartado.

 

g)       En UDP el uso del checksum es opcional; esto permite un rápido proceso de la información en transmisiones en tiempo real.

 

h)       El paso de IPv4 a IPv6 no requiere ningún cambio en TCP o UDP, ya que en la información de control (cabecera) de estos protocolos no aparecen direcciones IP.

 

i)         En un mismo host un número de puerto no puede ser utilizado simultáneamente por TCP y UDP

 

 

2.       Describa brevemente en que consiste la técnica conocida como 'slow-start'

 

 

3.       Explique la diferencia entre control de flujo y control de congestión.

 

 

4.       El tamaño máximo de un segmento TCP es 65.515 bytes. Podría explicar de donde viene este valor?

 

 

5.       Tanto el datagrama IP como el segmento TCP tienen un campo denominado checksum, que permite detectar errores de transmisión. Dado que TCP realiza la comprobación del checksum, ¿no resulta redundante que el nivel de red haga otra comprobación? Además, existe una diferencia importante en la manera como TCP e IP calculan el checksum, ¿sabe cual es?

 

 

6.       La fragmentación y reensamblado de datagramas es competencia de IP y se realiza de forma transparente a TCP. ¿Significa esto que TCP no tiene que preocuparse de que los datos le puedan llegar con el orden alterado?

 

 

7.       Una empresa dispone de un router con una interfaz ethernet y una línea serie, para conexión a la Internet, y desea configurar en él un filtro para que actúe de cortafuego. Se ha decidido que los empleados de la empresa podrán establecer conexiones TCP con el exterior, pero no se aceptarán conexiones TCP que se intenten establecer desde fuera (por ejemplo se podrá hacer telnet a máquinas de fuera de la empresa pero no se aceptará conexiones telnet desde fuera). De que forma se podría efectuar este filtrado?. El router tiene acceso a toda la información de cabecera del nivel de red y nivel de transporte, pero no a la parte de datos del nivel de transporte. Cuando recibe un datagrama el router sabe por que interfaz le ha llegado.

 

 

8.       Una aplicación genera un mensaje de 1540 bytes que entrega a TCP para su envío, el cual lo incluye en un segmento y lo pasa a IP para que lo envíe a su destino; no se utilizan campos opcionales ni en la cabecera IP ni en la cabecera TCP. La red inicialmente tiene un MTU de 4000 bytes, pero en algún punto del camino el datagrama ha de atravesar una red cuyo MTU es de 800 bytes. Indique cuantos datagramas y cuantos bytes recibe el nivel de red en el host de destino.

 

 

9.       Suponga que abre una sesión TCP entre dos hosts para transferir datos, y se reserva para dicha conexión una capacidad de 100 Mb/s (por ejemplo mediante RSVP). El tiempo de ida y vuelta es de 20 ms. ¿Sería posible ocupar en su totalidad el ancho de banda reservado? En caso negativo calcule cual sería el ancho de banda máximo que podría aprovecharse. Se supone que no se utilizan los campos opcionales de TCP y por tanto el tamaño máximo de ventana es el habitual.

 

 

10.    Suponga que utiliza slow-start en una línea con un tiempo de ida y vuelta de 10 milisegundos. La ventana receptora es de 24 KBytes y el tamaño máximo de segmento es de 2 KBytes. ¿Cuanto tiempo pasará antes de poder enviar la primera ventana completa? Suponga que no hay congestión.

 

 

11.    En una conexión TCP el valor promedio del tiempo de ida y vuelta MRTT es en un instante dado es de 30 mseg y los siguientes ACK llegan después de 26, 32 y 24 mseg respectivamente. ¿Cual es la nueva estimación de MRTT? Utilice a = 0,9.

 

 

12.    Suponga que realiza una conexión TCP a través de un medio físico poco fiable, es decir con un BER elevado. Como utiliza PPP a nivel de enlace el receptor comprueba el CRC y si la trama es erónea la descarta sin pedir reenvío al emisor. Como consecuencia de esto una de cada 10 tramas se pierde, con lo que el TCP emisor tiene que retransmitirla. No se produce fragmentación, por lo que cada segmento TCP se envía en una y solo una trama PPP.

 

a)       Indique como evolucionará la ventana de congestión en el TCP emisor si en la conexión se envían 50 segmentos de 1024 bytes cada uno. Suponga que TCP utiliza retransmisión selectiva y que el receptor no impone limitación por control de flujo al emisor.

 

b)       Indique cualitativamente que merma de rendimiento cabrá esperar en la conexión como consecuencia de la elevada tasa de error:

 

A: Menor del 10%

B: Alrededor del 10%

C: Mayor del 10%.

 

c)       Diga como influiría el valor del RTT (Round Trip Time) en su respuesta a la pregunta anterior.

 

Suponga que las tramas perdidas son justamente las número 10, 20, etc.

 

 


9.5      SOLUCIONES

 

 

S1.-

 

a)       Verdadero.

 

b)       Falso. Podría ocurrir que la dirección requerida se encuentre ya en la ARP cache del host (por ejemplo porque ya haya establecidas otras conexiones TCP entre esos mismos hosts, o porque haga poco tiempo que terminaron la anterior conexión), en cuyo caso no es necesario resolverla de nuevo.

 

c)       Falso. En ocasiones es suficiente un servicio menos 'fiable', como UDP.

 

d)       Falso. TCP utiliza un protocolo de ventana deslizante que permite enviar varios segmentos sin esperar confirmación.

 

e)       Falso. El bit PSH no garantiza el envío en segmentos independientes; por ejemplo si se utiliza el algoritmo de Nagle puede suceder que varios grupos de datos 'pushed' de la aplicación se envíen en un mismo segmento.

 

f)        Verdadero.

 

g)       Verdadero. Su uso es opcional en el emisor, pero no en el receptor. Si el emisor decide utilizar checksum el receptor deberá comprobar siempre su valor y descartar en caso necesario.

 

h)       Falsa. El cálculo del checksum en TCP y UDP incluye la pseudocabecera que esta formada entre otras cosas por las direcciones IP de origen y destino. El cálculo del checksum tiene por tanto que modificarse al pasar de IPv4 a IPv6.

 

i)         Falsa. Puede utilizarse sin ambigüedad, ya que ambos se diferenciarían por el campo protocolo del datagrama IP.

 

 

S2.-

 

Es una técnica de ventana deslizante de tamaño variable que permite a algunos protocolos de transporte (TCP por ejemplo) adaptarse por tanteos sucesivos al estado de la red, respondiendo a las situaciones de congestión - detectadas por la pérdida de un segmento - con una reducción drástica en el tamaño de ventana. En principio la ventana tiene de tamaño un segmento y se va duplicando en cada envío hasta llegar a un valor límite (normalmente 64 KBytes) o hasta que se produce la primera pérdida, momento en el que se establece un 'umbral de peligro' igual a la mitad del tamaño de la ventana en ese instante. A partir de ahí la ventana vuelve a crecer de forma exponencial como antes hasta llegar al umbral de peligro, a partir del cual solo crece de forma lineal, es decir en un segmento cada vez. Este proceso se repite indefinidamente mientras dure la conexión TCP.

 

 

S3.-

 

El control de flujo se establece en una conexión extremo a extremo entre dos entidades (a nivel de enlace o a nivel de transporte) para evitar que un emisor activo sature a un receptor lento o sobrecargado. El control de congestión se establece en una red para evitar que se produzca saturación en alguna línea, lo cual provocaría la pérdida de paquetes y por consiguiente una merma en el rendimiento de toda la red.

 

 

S4.-

 

La cabecera de un datagrama IP tiene un campo de 16 bits que especifica la longitud total del datagrama, por lo que ésta puede ser como máximo de 65535 bytes. De estos al menos 20 corresponden a la cabecera IP, por lo que la longitud máxima de un segmento TCP puede ser como máximo 65515 bytes. La máxima cantidad de datos que puede transportar un segmento TCP es de 65495 bytes (65515 menos 20 de la cabecera TCP sin opciones).

 

Advertencia: En el Tanenbaum (pag. 526) hay un cálculo equivocado de la cantidad de datos que como máximo puede contener un segmento TCP. Dicha cantidad no es 65515 sino 65495 bytes por lo que se ha explicado.

 

 

S5.-

 

El nivel IP realiza la comprobación en cada salto, mientras que TCP la realiza únicamente en el host de destino. El checksum de IP sólo comprueba la información de la cabecera IP, no la cabecera TCP ni la parte de datos. El checksum de TCP comprueba tanto su cabecera como los datos, y añade una pseudocabecera que le permite verificar los datos fundamentales de la cabecera IP (dirección origen, dirección destino, protocolo y longitud del segmento).

 

Debido a que se ha de calcular múltiples veces el checksum de IP se intenta que sea sencillo y rápido de calcular, mientras que el de TCP puede ser exhaustivo ya que solo se comprueba una vez. La comprobación de IP permite detectar errores en la información de control que podrían encaminar un datagrama al destino equivocado, pero nada mas. Por otro lado la inclusión de la pseudocabecera en el checksum de TCP le permite detectar si el datagrama ha sido entregado al destino incorrecto, aun en el caso de que falle la comprobación de IP.

 

 

S6.-

 

En el caso de que un segmento se fragmente TCP no tendrá que preocuparse del orden de los fragmentos, ya que el nivel IP del receptor le presentará el segmento tal como estaba antes de la fragmentación. Sin embargo si datagramas que corresponden a segmentos diferentes llegan desordenados IP no los ordena, ya que no hay campo en la cabecera IP que especifique el orden de emisión. En tal caso será el TCP del receptor el que, ayudado de los números de secuencia, se ocupe de reordenar los diferentes segmentos en su buffer antes de pasar la información a la aplicación correspondiente.

 

 

S7.-

 

El router debería filtrar, es decir descartar, todos los datagramas que le lleguen por la interfaz serie y que cumplan simultáneamente las dos condiciones siguientes:

 

o    Tener el valor 6 en el campo protocolo de la cabecera IP (esto indica que el datagrama contiene un segmento TCP).

 

o    Tener a 1 el bit SYN y a 0 el bit ACK de los flags de la cabecera TCP. Estas dos características solo se dan en un segmento que intente iniciar una conexión TCP desde fuera.

 

Normalmente al descartar el datagrama el router debería enviar un mensaje ICMP DESTINATION UNREACHABLE al emisor, explicando en el código del mensaje el motivo por el cual ha sido rechazado.

 

 

S8.-

 

El segmento creado por TCP tendrá una longitud de 1560 bytes; ésta será la información que se fragmente a nivel IP. Como el MTU es de 800 bytes en cada datagrama se ocuparán 20 bytes con la cabecera IP y quedarán 780 para transportar el segmento; pero como los fragmentos han de tener una longitud múltiplo de 8 en realidad solo se pueden aprovechar como mucho 776 bytes de cada datagrama; necesitamos por tanto enviar tres datagramas que tienen la siguiente estructura:

 

Cab. IP  (20 Bytes)

Cab. TCP (20 Bytes)

Datos (756 Bytes)

 

Cab. IP  (20 Bytes)

Datos (776 Bytes)

 

Cab. IP  (20 Bytes)

Datos     (8 Bytes)

 

En total se envían tres datagramas y 1620 bytes. Obsérvese que el proceso de fragmentación no altera ni el número de segmentos enviados ni la cantidad de bytes transmitidos a nivel TCP.

 

 

S9.-

 

La máxima cantidad de datos que una sesión TCP puede enviar sin esperar acuse de recibo es igual al tamaño máximo de ventana, 64 KBytes – 1 o sea 65535 bytes, que equivalen a 524.280 bits. Vamos a suponer en primer lugar que los TCPs hubieran negociado un tamaño máximo de segmento igual al tamaño máximo de ventana. Si el envío se hace en segmentos de 65535 bytes el TCP emisor funcionando a 100 Mb/s necesitará 5,24 ms para introducir el segmento en la línea de transmisión y luego tendrá que esperar 20 ms mas hasta recibir el ACK correspondiente (suponiendo que el tiempo empleado en generar el ACK por parte del TCP receptor sea despreciable). Una vez recibido el ACK se enviará otro segmento durante 5,24 ms y se esperará 20 ms para recibir la respuesta. Se irán pues alternando períodos de 5,24 ms de actividad y 20 ms de espera, con lo que el funcionamiento será similar a un protocolo de parada y espera; y la tasa de ocupación de la línea será de 5,24/(5,24+20) = 0,208 = 20,8 % = 20,8 Mb/s.

 

Si en vez de utilizar segmentos de 64 KBytes empleamos segmentos por ejemplo de 1 KByte los ACKs empezaran a producirse tan pronto llegue la primera trama, sin necesidad de esperar a que el receptor reciba los 64 Kbytes de información. Con esto solapamos el tiempo de generación (que es ahora de 0,08 ms) y el tiempo de ida y vuelta (20 ms), dando una eficiencia mas alta; veamos en detalle lo que ocurre:

 

0 ms                        El TCP emisor empieza a enviar el primer segmento.

0,08 ms                  El TCP emisor empieza a enviar el segundo segmento.

0,16 ms                  El TCP emisor empieza a enviar el tercer segmento.

5,16 ms                  El TCP emisor empieza a enviar el segmento número 64

5,24 ms                  El TCP emisor termina de emitir el segmento número 64 y queda a la espera.

10 ms                     El TCP receptor empieza a recibir el primer bit del primer segmento.

10,08 ms                Llega al receptor el último bit del primer segmento; se devuelve un segmento

vacío con el ACK correspondiente.

20,08 ms               Llega al TCP emisor el primer ACK; empieza a enviarse el primer bit del segmento número 65.

 

A partir de aquí el ciclo se repite. Conseguimos pues tener la línea ocupada 5,24 ms de cada 20,08 ms, con lo que el rendimiento será de 5,24/20,08 = 0,261 = 26,1 % = 26,1 Mb/s. La mejora en la eficiencia se debe en este caso al uso de ventana deslizante.

 

En el caso límite, con segmentos muy pequeños, se conseguiría un total solapamiento entre los tiempos de transmisión (5,24 ms) y de propagación (20 ms): 5,24/20 = 0,262 = 26,2 % = 26,2 Mb/s.

 

Por tanto no podría utilizarse todo el ancho de banda reservado, sino solamente 26,2 Mb/s como máximo.

 

Una forma mas rápida de calcular la respuesta anterior sería haber utilizado la fórmula:

 

Tamaño de ventana = capacidad * RTT

 

Sabiendo que RTT = 20 ms y que el tamaño de ventana es 64 Kbytes, despejamos la capacidad:

 

Capacidad = Tamaño de ventana / RTT = 64 * 1024 * 8 / 0.02 = 26,2 Mb/s

 

Para un total aprovechamiento de la línea habría que utilizar la opción de TCP que permite ampliar el tamaño de la ventana, ya que así podríamos 'llenar' de datos la línea de transmisión y suprimir los tiempos de espera; la ventana mínima que nos permitiría hacer esto sería:

 

 

Tamaño ventana = 100 * 106 * 20 * 10 -3 = 2 * 106 bits

 

2 * 106 bits / 8  = 250000 bytes

 

250000 bytes / 1024 = 244,1 KBytes

 

 

S10.-

 

El crecimiento de la ventana se producirá de la siguiente forma:

 

 

Ciclo

Número de segmentos

Cantidad de KBytes

Tiempo transcurrido (ms)

Primero

1

2

0

Segundo

2

4

10

Tercero

4

8

20

Cuarto

8

16

30

Quinto

12

24

40

 

 

Por tanto la respuesta es: 40 milisegundos.

 

 

S11.-

 

Los valores de MRTT calculados son sucesivamente 29,6, 29,84 y 29,256 milisegundos.

 

 

S12.-

 

a)       Como funcionamos con repetición selectiva cuando se pierde una trama solo se reenvía el segmento correspondiente a dicha trama.

 

Aquí es importante distinguir las tramas de los segmentos. Para ello usaremos la notación Tm(Sn) donde m indica el número de trama y n el número de segmento. A efectos de los errores producidos consideraremos que las tramas nunca se repiten, lo que se reenvía en caso necesario son los segmentos.

 

La siguiente tabla muestra la evolución de la ventana de congestión; en negritas aparecen los envíos perdidos. Como era previsible se envían 55 tramas y 50 segmentos.


 

Ventana de congestión (KBytes)

Tramas(Segment.) enviados

Umbral de peligro (KBytes)

1

T1(S1)

64

2

T2(S2)

T3(S3)

"

4

T4(S4)

T5(S5)

T6(S6)

T7(S7)

"

8

T8(S8)

T9(S9)

T10(S10)

T11(S11)

T12(S12)

T13(S13)

T14(S14)

T15(S15)

"

1

T16(S10)

4

2

T17(S16)

T18(S17)

"

4

T19(S18)

T20(S19)

T21(S20)

T22(S21)

"

1

T23(S19)

2

2

T24(S22)

T25(S23)

"

3

T26(S24)

T27(S25)

T28(S26)

"

4

T29(S27)

T30(S28)

T31(S29)

T32(S30)

"

1

T33(S28)

2

2

T34(S31)

T35(S32)

"

3

T36(S33)

T37(S34)

T38(S35)

"

4

T39(S36)

T40(S37)

T41(S38)

T42(S39)

"

1

T43(S37)

2

2

T44(S40)

T45(S41)

"

3

T46(S42)

T47(S43)

T48(S44)

"

4

T49(S45)

T50(S46)

T51(S47)

T52(S48)

"

1

T53(S46)

2

2

T54(S49)

T55(S50)

"

 

 

b)       En principio atendiendo solo a la cantidad de datos retransmitidos cabría esperar una merma del rendimiento de un 10% aproximadamente (se envían 55 tramas para 50 tramas útiles). Sin embargo, el hecho de que cada trama perdida provoque la reducción a 1 de la ventana de congestión y el reinicio del mecanismo de 'slow-start' produce una merma que será con toda seguridad superior al 10%.

 

c)       El valor de RTT influye de forma decisiva en lo dicho anteriormente. En el caso límite en que el RTT fuera nulo la reducción sería exactamente del 10%, ya que no habría penalización por el hecho de tener que reinciar el 'slow-start' cada vez (con RTT nulo da lo mismo tener una ventana grande que pequeña, ya que no hemos de esperar para recibir el ACK).

 

En el caso real en que el RTT no sea cero la merma de rendimiento será tanto mayor cuanto mayor sea el RTT de la conexión TCP.

 



[1] Si por ejemplo la transacción consiste en la transferencia de dinero entre cuentas bancarias se realizarían dos trasferencias en vez de una.

[2] La denominación socket empleada para la combinación IP.puerto es la misma que la de las APIs utilizadas en UNIX para acceder a los servicio TCP.

[3] En realidad esta afirmación solo es correcta cuando se utiliza telnet con eco local; en la mayoría de los casos el telnet utiliza eco remoto, es decir el telnet remoto (servidor) ha de procesar lo que se teclea carácter a carácter, realizando la representación en pantalla si procede. Cuando se funciona con eco remoto el telnet cliente pone el bit PUSH para cada carácter que se teclea. Aunque es mucho menos eficiente que el eco local el eco remoto es hoy en dia la forma de funcionamiento más habitual, ya que muchos editores de pantalla completa (el vi por ejemplo) necesitan eco remoto para funcionar correctamente.

[4] Se suelen preferir en estas fórmulas los factores que son potencias enteras de 2 en el denominador ya que esto hace más sencillos, y por tanto más rápidos, los cálculos.

[5] En realidad la capacidad efectiva en IP de un enlace OC-3 después de restar el overhead de SDH y ATM es de unos 135 Mb/s, por lo que sería suficiente con una ventana de 132 Kbytes.

[6] La arquitectura de NFS presupone la no existencia de una conexión entre el servidor y el cliente, razón por la cual se adapta mejor a funcionar sobre UDP. En principio NFS fue una aplicación diseñada para su uso en redes locales, donde el retardo suele ser bajo y constante y la pérdida de datagramas muy rara. En este entorno UDP da normalmente un rendimiento aceptable. Sin embargo cuando se utiliza NFS en redes de área extensa el rendimiento puede no ser satisfactorio debido a la mayor fluctuación del retardo y la pérdida de datagramas debido a congestión. Para resolver estos problemas algunos fabricantes han desarrollado implementaciones de NFS que utilizan TCP como protocolo de transporte. Aunque supone una mejora interesante esto no está ampliamente disponible.