CAPÍTULO XII Transferencia de datos TCP En el capítulo previo se han presentado los aspectos más significativos del protocolo TCP relacionados con el inicio y fin de una conexión. Muchos de ellos se plasman en los campos del encabezado, pero otros comportamientos surgen de las transiciones explicadas a partir del Diagrama de Estados. En este capítulo se presentará el protocolo en acción, una vez que la conexión se ha establecido. Se desarrollará en detalle la estrategia de expiración (timeout) y retransmisión y el ajuste de los parámetros que la manejan. Se explicará cómo afronta TCP situaciones de pérdida de segmentos, aparición de segmentos duplicados y casos de desorden en los segmentos recibidos, debiendo asegurar, en cualquier caso, una comunicación confiable. El capítulo abordará la dinámica que el protocolo imprime sobre la transferencia de datos, distinguiendo entre los casos de aplicaciones interactivas, donde la transmisión es de pocos bytes por vez, y la transferencia de grandes volúmenes de datos. 12.1 Estrategia de expiración y retransmisión Cada segmento enviado por TCP, lleva asociado un reloj de descuento o expiración (timeout) que, si se agota sin que se reciba un segmento cuyo Número de ACK cubra los datos transportados en el segmento transmitido, dispara la retransmisión. El tiempo se asocia a una variable conocida como Expiración de Retransmisión (RTO, Retransmission Timeout). La estrategia significa que el reloj debe ajustarse de manera de dar tiempo a bajar el segmento a la red, que ésta lo transporte encapsulado en IP hacia destino, que el destino lo levante de la red y verifique sus errores y, de ser correcto, que edite un segmento ACK para que viaje de regreso hacia la fuente. Todo este tiempo se conoce como Tiempo de Viaje de Ida y Vuelta (RTT, Round Trip Time). En el capítulo previo, se ha mencionado que existe un tiempo de expiración asociado al inicio de una conexión. Su naturaleza es del tipo retroceso exponencial, manejado por dos variables: la cantidad de reintentos y el tiempo total antes de proceder a un aviso de imposibilidad de comunicación. Estos valores podrían fijarse de antemano, en términos generales, suficientes para cubrir cualquier tipo de conexión. Lo interesante, durante la fase de transmisión de datos para una conexión particular, y aún dentro de una misma conexión, es cómo fijar el valor del RTO, ya que el propio RTT puede llegar a variar por diversos motivos, muchos de los cuales se encuentran asociados directamente a la situación de carga de tráfico en la red. 439 La estrategia más inteligente en todos los casos sería fijar el valor del RTO en base a una medición del RTT. Esto es lógico cuando se piensa que, si se fijara el valor del RTO en un tiempo menor que el RTT promedio para la conexión particular, probablemente se producirían retransmisiones innecesarias. De la misma manera, si se fija un valor superior, se podría perder capacidad de reacción, trabajándose de manera ineficiente en el caso de una red congestionada. Por este motivo, el valor fijado para el RTO debe seguir las propias fluctuaciones del RTT. Para cada conexión, el protocolo TCP toma muestras del valor del RTT, midiendo el tiempo que transcurre entre la transmisión de un segmento de datos con un Número de Secuencia dado y la recepción de un segmento de ACK, cuyo Número de ACK lo reconozca como recibido correctamente. Dentro de una misma conexión, se pueden obtener muchas muestras que pueden servir para estimar las variaciones del RTT, para el ajuste apropiado del RTO. La estimación debe ser lo más cercana posible a la realidad para no generar retransmisiones disparadas prematuramente, innecesarias, o tardías, por falta de capacidad de reacción a las variaciones. 12.1.1 Cálculo del Estimador Suavizado en el Método Clásico Originalmente, en la RFC 793, se ofrecía un ejemplo de cálculo de un Estimador Suavizado del RTT (SRTT, Smoothed RTT), según la siguiente relación: = + 1 − (12.1) En la Ec. (12.1), es la medición actual del tiempo de ida y vuelta y del lado derecho de la igualdad es la estimación previa. Con ambos valores, pesados de manera apropiada, se obtiene el nuevo valor de . El factor de suavizado determinará el peso que la última medición, o el valor previo estimado, tendrán sobre la nueva estimación. Un valor común recomendado para era 0.8ó0.9, obteniendo el 80%ó90% de la nueva estimación, a partir de la estimación previa, y sólo el 20%ó10% a partir de la medición actual. Una vez calculado el estimador, la RFC 793 establecía el valor de como: = min, max , ! (12.2) En esta expresión, se refiere a un límite superior recomendado en 1"# y a un límite inferior recomendado en 1$%&. El parámetro ! se define como la varianza del retardo, cuyo valor recomendado se encontraba en el rango 1.3(2. En términos prácticos, el valor de , terminaba fijado en 1$%& o el doble del estimador. Esta medición funcionaba correctamente en conexiones estables, sin grandes variaciones de . 440 12.1.2 Cálculo del Estimador Estándar de Jacobson En 1988, Van Jacobson publicó un artículo en el que observaba que la estimación clásica resultaba apropiada para cierto nivel de carga, a partir del cual la conexión respondería al incremento con retransmisiones de paquetes que sólo habrían sido retrasados en tránsito. En esas situaciones de congestión, los paquetes duplicados cargaban aún más la red. Por este motivo, propuso un nuevo método de estimación, en el que calculaba el error entre la estimación y la medición, luego el valor medio de la estimación y, por último, el valor medio de la desviación. En su explicación, Van Jacobson comenzó reordenando la ecuación original, definiendo 1 − = & , de tal manera que la expresión (12.1) se puede volver a escribir como: = + & − (12.3) En esta ecuación, el error es la diferencia − , por lo que la nueva predicción de la estimación queda determinada por la predicción previa y una fracción del error. Van Jacobson consideró el error compuesto por dos componentes, un componente aleatorio, propio de las fluctuaciones de tráfico )* , y otro debido a una mala elección del estimador )+ . De este modo la Ec. (12.3) anterior se convierte en: = + &)* + &)+ (12.4) Una de las cuestiones principales es la elección del factor &. Según Jacobson, el término aleatorio)+ mueve el valor de hacia el valor medio real, sin importar el valor de & usado, pero un valor pequeño de & mimimiza la influencia de esta componente aleatoria. Por este motivo, aconsejó un valor en el rango 0.1(0.2 . El valor estimado oscilará aleatoriamente alrededor del promedio verdadero y la desviación estándar será la del valor medido , convergiendo con una contante de tiempo 1, . Para medir la desviación estándar de , Jacobson desechó la varianza, puesto que eso & implicaba el cálculo de un cuadrado, − - , y luego de una raíz, complicando la implementación. Por este motivo, en lugar de la desviación estándar, propuso calcular la desviación media, por provenir de un cálculo más conservador y mantener una relación mayor, pero cercana a uno, con la desviación estándar, siempre que los errores de predicción tengan una distribución normal. Basado en estas premisas, propuso el siguiente cálculo: ).. = / − 0 0 ← 0 + &).. 2 ← 2 + ℎ|)..| − 2 = 0 + 42 (12.5) 441 En este conjunto de ecuaciones, / es el valor medido, 0 es el estimado y 2 la desviación media. Para que el cálculo sea rápido debería ser realizado en aritmética de números enteros, pero como & < 1 es un número no entero, impuso un escalamiento para las expresiones previas. Jacobson propuso & = 1,8 y ℎ = 1,4, para que fuera más sencillo escalar mediante corrimientos binarios, y porque la mayor ganancia para la desviación permite al seguir mejor las variaciones del . La RFC 6298 recomienda ajustar los valores iniciales para en 1$%& , cuando la conexión recién comienza y no se han podido realizar mediciones. Este valor se eleva a 3$%& en el caso que el primer segmento SYN no logre llegar al otro extremo o se pierda el ACK que lo cubre. Una vez conseguida una primera medición del , se recomienda inicializar los estimadores a (0 ← / y (2 ← /,2. El método de Jacobson es la base sobre la que muchas implementaciones TCP calculan el hoy en día, logrando adaptarse de manera apropiada a los vaivenes de la conexión. 12.1.3 Problema de la medición en las retransmisiones - Algoritmo de Karn La medición del presenta un problema en el caso de dispararse una retransmisión. Cuando se transmite un segmento, si no se recibe el ACK correspondiente, dentro del establecido, se procede a su retransmisión. Si posteriormente llegase un ACK para dicha retransmisión, no sería posible determinar con certeza si se corresponde a la transmisión o a la retransmisión. Surge entonces la pregunta sobre a cuál de ambos se asocia la medición. Este problema, que se conoce como ambigüedad del ACK, fue estudiado por Phil Karn, quien determinó que no era preciso asociar una medición a esta situación para luego calcular el estimador. La RFC 6298 también estableció que no se deben tomar muestras del sobre segmentos retransmitidos, excepto que los segmentos carguen la nueva opción de sello de tiempo, con la que se puede remover la ambigüedad. De todas maneras, el hecho de haber tenido que retransmitir, permite obtener información sobre el estado de la red, ya que TCP interpreta una situación de timeout como un indicador de congestión. No tendría sentido entonces seguir usando el mismo valor de , ya que probablemente disparará nuevas retransmisiones. Lo más sensato sería aumentar el valor de para reducir la carga sobre la red. A instancias de lo observado por Karn, TCP incorpora para estos casos un factor de backoff para el , que se duplica con cada nueva retransmisión. Esta situación se mantiene mientras no se pueda realizar una medición correcta, sobre un segmento no retransmitido. Entonces, el valor del factor de backoff vuelve a 1 y el valor de se calcula a partir de los estimadores. 442 12.1.4 Opción Sello de Tiempo para medición de RTT La RFC 1323 define una opción TCP, conocida como Sello de Tiempo, que puede usarse para lograr una medición más precisa del . En caso de usar esta opción, para tomar una muestra del valor de se agrega al encabezado un número de 32#7$ , que luego es copiado por el otro extremo en el segmento ACK. Se puede medir el registrando el tiempo de transmisión del segmento y la llegada del ACK con el valor de Sello de Tiempo correspondiente, y restando ambos valores entre sí. Aunque se pueden lograr mediciones más precisas con este mecanismo, es necesario acompañarlo de reglas para diferentes situaciones de medición, tal como se explicará en el siguiente Capítulo. 12.1.5 Algoritmo de Manejo del RTO La RFC 6298 indica un algoritmo recomendado para el manejo del reloj de retransmisión: 1. Cada vez que se envía un segmento con datos, aunque se trate de una retransmisión, hay que encender el reloj que expirará luego de $%& (para el valor actual del ). 2. Cuando todos los datos pendientes se hayan reconocido, apagar el reloj. 3. Cuando se reciba un ACK para datos nuevos, re-arrancar el reloj para que expire luego de $%&. Cuando el reloj expire, se debe: 4. Retransmitir el segmento más viejo que no haya sido reconocido. 5. Ajustar el valor = 2 (reloj de backoff). El valor máximo de RTO debe ser, por lo menos, de 60$%&. 6. Arrancar el reloj de retransmisión para que expire luego de $%&. 7. Si el reloj expira mientras espera la llegada de un ACK para un segmento SYN y la implementación está usando un valor de < 3$%&, se debe re-inicializar el a 3$%& cuando comience la transferencia de datos. Luego de una retransmisión, cuando se hayan enviado nuevos datos y recibido un ACK para ellos, se puede obtener una nueva medición para , y un cálculo para , que puede provocar una disminución en el valor fijado por el backoff. 12.1.6 Retransmisiones y re-empaquetado Una cuestión a tener en cuenta es que, al momento de que se produce una expiración del , se dispara una retransmisión, aunque no necesariamente del mismo segmento. TCP puede re-empaquetar datos, transmitiendo un segmento de mayor tamaño por cuestiones de eficiencia. Esta funcionalidad es posible por la forma de numerar los datos que adopta el protocolo: por byte y no por segmento. 443 12.2 Aplicaciones interactiv nteractivas Una aplicación interactiva que se apoya en TCP precisa que mensajes de poco volumen de datos se transmitan entre cliente y servidor: un carácter de teclado, un movimiento del mouse o de un joystick. Estos pequeños mensajes provocan acciones del lado servidor. servi Se trata de paquetes denominados tynigrams, t por diminutos o tiny, ya que son de muy pocos bytes, razón por la que su transmisión resulta ineficiente, ineficiente debido al gran gasto u overhead que representa el encabezado frente a la carga de datos. Por otra parte, rte, si se eligiera transmitir varios de estos paquetes en uno solo, se podrían generar situaciones molestas para el usuario, usuario debido a que las aplicaciones interactivas son sensibles al retardo. Se suele distinguir este tipo de transporte respecto del tráfico tr de grandes volúmenes de datos. La mayoría del tráfico TCP es de este último tipo pero, a pesar de ello, el protocolo mantiene reglas especiales para el transporte de tráfico interactivo. Un ejemplo de viejas aplicaciones que generaban este tipo de tráfico son rlogin y telnet. Ambas permitían el login remoto, aunque padecían de muchos inconvenientes en cuanto a seguridad. Una aplicación más nueva, denominada SSH, por Secure Shell Shell, trabaja de forma similar a telnet, pero usa técnicas de cifrado, cifrado, logrando que el tráfico sea mucho más seguro frente a la instalación de sniffers. Un flujo de datos típico de este tipo de aplicaciones interactivas se presenta en la Fig. 12.1. Figura 12.1 1 – Flujo de Datos Interactivo En este caso, cada ada tecla presionada presionada por el usuario genera un segmento que via viaja por la red hasta el servidor. Éste debe hacer eco de lo que el cliente escribe, escribe, para que el usuario lo pueda apreciar en su pantalla.. Con esta forma de operación,, la transmisión de un único carácter, pueden en generar hasta cuatro segmentos: segmen el de datos y su correspondiente ACK, y el de eco y su propio ACK. En la Fig. 12.1 1 se puede observar que, luego de la llegada del primer dato al lado servidor, se retrasa retras el segmento de ACK que lo reconoce,, probablemente en espera de poder cargar el eco, para hacer la transmisión más eficiente. 444 Figura 1 12.2 – Flujo de Datos Interactivo Normalmente, el lado servidor es lo suficientemente rápido como para combinar ambos segmentos, tal como se observa en la Fig. 12.2. Esta técnica de combinación de ACK con datos se conoce con el nombre de piggybacking, que significa montado a caballito caballito. Del lado cliente, sin embargo, no se puede juntar el ACK con el siguiente dato, pues esto depende de la rapidez con que ell usuario maneje el teclado. La técnica de ACK retardado es una técnica muy usada por el protocolo TCP. Lo cierto es que no se puede retrasar el envío del segmento ACK sin que se ponga en juego cierta probabilidad de retransmisión. Por este motivo, la RFC RFC 1122 establecía un máximo de 500"$%& al tiempo de retraso,, pero muchas implementaciones lo ajustan en 200"$%& "$%&. Hemos mencionado ya que TCP utiliza una técnica conocida como ACK acumulativo acumulativo, con la cual no es preciso generar un ACK por cada segmento recibido. Siguiendo este criterio, el protocolo puede demorar la generación de un ACK,, a la espera de poder combinarlo con el envío de datos. La Fig. 12.2 .2 presenta el caso en que la implementación posee un límite de 200"$%&, resaltando ndo el hecho de que las transmisiones de segmentos ACK se disparan a partir de un reloj interno del mismo período. 12.2.1 Algoritmo de Nagle Para poder manejar de manera eficiente situaciones de paquetes pequeños inyectados en la red, TCP incluye el Algoritmo oritmo de Nagle, Nagle que se basa en la existencia de ACK retardados y se encuentra descripto en la RFC 896. 896 El algoritmo establece que, ccuando uando una conexión tiene datos en el buffer de transmisión a la espera de ACK,, no puede transmitir nuevos datos bajados por el usuario en forma de segmentos pequeños,, hasta que los datos no reciban el correspondiente ACK. De este modo, no sólo se busca juntar junta cierta cantidad de datos en un segmento,, transmitiéndolo cuando se reciba el ACK,, sino además se s agrega características de auto-sincronismo sincronismo a la propia 445 conexión, ya que cuanto más rápido se reciban segmentos ACK, más pronto se transmitirán los datos. Un detalle importante es que la aplicación del algoritmo es diferente según el entorno. Por ejemplo, si la conexión se ha establecido entre dos máquinas en una misma red LAN, cuyo retardo ida y vuelta es mucho más pequeño que 1"$%&, se precisaría que el usuario fuera capaz de manejar el teclado a una velocidad superior a 1000:(.(:7%.%$/$%& para poder observar el algoritmo trabajando. En este entorno, el Algortimo de Nagle no se dispara, puesto que el segmento de ACK siempre llega antes que el siguiente carácter en el buffer. En un entorno WAN, sin embargo, se modifican bastante los tiempos, pudiendo llegarse a retardos en el orden de los segundos. En este caso, un usuario generando caracteres a razón de 1:(.á:7%./$%&, aumenta la probabilidad de que el Algoritmo de Nagle se dispare, colectando datos antes de que llegue un ACK. De esta manera, se reducirá el número de paquetes pequeños en la red aunque la conexión se verá afectada, probablemente aumentado la duración total de la misma, debido a la característica de auto-sincronismo impuesta. Generalmente, el Algoritmo de Nagle se encuentra habilitado por default, pero hay ocasiones, en entornos altamente interactivos, donde los efectos de performance que genera pueden ser indeseables con respecto a la latencia. Por este motivo, se lo puede deshabilitar sobre una base por conexión, a través de una opción de socket(). 12.3 Tratamiento de datos - Bandera PSH Mientras que las aplicaciones manejan la velocidad y el momento con que envían datos a TCP, no pueden controlar ni la velocidad ni el tiempo con que TCP los envía a la red. En el caso de transmisiones de grandes archivos esto no sería un problema mientras TCP acumulara los datos en buffer y los fuera transmitiendo a medida que la conexión lo permitiese. En el caso de una aplicación interactiva, no se desea que TCP acumule los datos, sino que los transmita lo más rápidamente posible, para que no se perciban demoras en el proceso interactivo. Para manejar esas situaciones se incluyó la bandera de PUSH en el encabezado TCP. Cuando se invoca esta funcionalidad, TCP creará un segmento o varios que contengan los datos en espera y los transmitirá con la bandera de PUSH en alto. Los límites de los mensajes dependen de las aplicaciones. En la práctica se suele encender esta bandera cuando se vacía el buffer de transmisión, toda vez que se transmite un segmento. 12.4 Tratamiento de datos - Bandera URG El protocolo TCP permite que las aplicaciones marquen datos que precisan tratamiento urgente. Cuando se envían datos de este tenor para ser transmitidos, levantan la bandera URG del encabezado, indicando que el campo Puntero URG es válido. 446 El mecanismo urgente de TCP permite marcar un punto en el flujo de bytes como el final de la información que precisa tratamiento urgente. Siempre que dicho número sea mayor que el extremo izquierdo de la ventana de recepción (RCV.NXT), el protocolo receptor debe avisar a la aplicación para que ésta entre en modo urgente. Cuando el borde izquierdo de la ventana de recepción haya alcanzado el número de byte que marca el puntero urgente, TCP debe avisar a la aplicación que puede volver al modo normal de operación. Esto significa que ciertos datos que fueron recibidos como normales, podrían convertirse en datos urgentes si se recibe una indicación URG en un segmento posterior, antes que dichos datos hayan sido subidos a la aplicación. El último byte de datos urgentes se encuentra sumando el campo Número de Secuencia con el valor del campo Puntero Urgente, cargados en el segmento con la bandera URG levantada. Este mecanismo presentó varias ambigüedades desde el momento de su definición. No se trata de un mecanismo de entrega de datos fuera de banda, pero muchas implementaciones procesan los datos urgentes de ese modo, no entregándolos como parte del flujo de datos normal, como lo especifica la RFC original, sino separando el último byte de datos urgente . También, durante muchos años existió una ambigüedad referida a si el puntero urgente apuntaba al primero o al último byte de datos urgentes, hasta que la RFC 1011 aclaró que se trata del último byte. Como consecuencia de estas cuestiones, la RFC 6093 aconsejó que las nuevas aplicaciones no usaran el mecanismo urgente de TCP, aunque estableció que todas las implementaciones TCP lo deben seguir incorporándolo para que pueda ser utilizado por aquellas aplicaciones ya existentes que lo invocan. 12.6 Flujo de grandes volúmenes de datos En contraposición con el tráfico de aplicaciones interactivas, el 90% de las transmisiones TCP se refiere a intercambio de grandes volúmenes de datos. A continuación, se presentan varios ejemplos de transferencias de datos entre un cliente y un servidor web. En algunos casos, se ha omitido el inicio de la conexión y se ha numerado los segmentos con un número de secuencia relativo, a partir del número “0”, reservado para el primer byte de datos de cada extremo. Los números entre corchetes “? @” representan la carga de datos de cada segmento. Resaltado junto al instante de transmisión de cada segmento aparece un número indicador del orden del mismo en el flujo de datos TCP. 12.6.1 Intercambio de segmentos – Situación de timeout En la Fig. 12.3, se presenta parte de una transferencia de datos entre un cliente y un servidor web. La intención de este ejemplo es ver al protocolo en acción en una transferencia de segmentos con gran cantidad de datos y situaciones de timeout. Se aconseja al lector seguir el flujo de Números de Secuencia y Números de ACK para entender mejor cómo trabaja TCP. 447 448 Figura 12.3 .3 – Flujo de grandes volúmenes de datos El segmento 1 es un pedido GET del cliente HTTP, que carga 1010A7%$ A7%$ de datos y anuncia un tamaño de ventana de 251A7%$. Es dable aclarar que ste valor de ventana, debería escalarse, puesto que ambos extremos negociaron en el inicio la utilización de la opción Escalamiento de Ventana Ventana, que acá se omite. Por lo tanto, lo mismo debería interpretarse a partir de los valores de ventana anunciados por el servidor. 449 En el segmento2, el servidor reconoce todos los datos provenientes del cliente, mediante un ACK retardado, o sea un segmento sin datos, únicamente transmitido para reconocimiento de los datos recibidos. Es preciso hacer notar que, un segmento ACK sin datos, lleva el número de secuencia que el otro extremo está esperando recibir, que también será el número de secuencia del siguiente segmento de datos que el cliente transmita. El servidor comienza a transmitir datos en los segmentos 3 y 4. Primero transmite 590A7%$ y luego 222A7%$, que son reconocidos en conjunto con un ACK retardado proveniente del cliente, cuyo número de secuencia es 1010. El número de ACK es la suma 590 + 222 = 812. En el segmento 6, el cliente realiza un nuevo pedido, de 1018A7%$ de datos. Su número de secuencia es 1010, porque esa fue la cantidad de datos transmitida en el primer segmento, cuyo número de secuencia se fijó en “0”, para numeración relativa. El servidor reconoce la llegada correcta de estos nuevos datos con el ACK retardado del segmento 7. Los segmentos 8 y 9 son la respuesta al requerimiento, transmitida en dos paquetes de523 y 223A7%$ de datos, respectivamente. Obsérvese en ambos extremos las leves variaciones de la ventana anunciada, sin olvidar que está escalada. En el segmento 10 se puede observar un caso de piggybacking: el cliente reconoce todos los bytes recibidos y aprovecha la transmisión del segmento de ACK para enviar 1018A7%$ de datos. Con el segmento 11, el servidor sólo reconoce una parte de los datos recibidos. En los segmentos 12 y 13, el servidor envía en total 384A7%$ de datos, pero no reconoce nuevos datos recibidos. La llegada correcta de estos datos al lado cliente se reconoce en el segmento 14, otro ACK retardado. Evidentemente, este segmento ACK se pierde y el extremo servidor se ve obligado a retransmitir estos datos en el segmento 15. Esto es evidente en el Número de Secuencia del segmento 15. Vale la pena destacar que la situación de timeout es una indicación fuerte de congestión para TCP. Por otra parte, el segmento 15 es una muestra de lo que en TCP se conoce como re-empaquetado o repacketization: en lugar retransmitir los datos en dos segmentos, como se habían transmitido originalmente, el protocolo realiza la retransmisión juntando ambos segmentos en uno. El cliente reconoce la retransmisión en el segmento 16 y, posteriormente, en el segmento 17, transmite más datos. Luego, el lado servidor transmite un segmento con 384A7%$ de nuevos datos, tal como lo indica su Número de Secuencia. Los segmentos 19 y 20 representan una repacketization de estos datos para su retransmisión. El segmento 21, proveniente del cliente, reconoce los datos previos y el segmento 22 carga 631A7%$ de un pedido del cliente, que se reconocen en el segmento 23. Los segmentos 24 y 25 son dos nuevas transmisiones del servidor. El segmento 26 es un ACK retardado del lado cliente. En el segmento 27, el cliente envía datos, que el servidor reconoce en el segmento 28. Nuevamente el servidor transmite dos segmentos, que el cliente reconoce con un ACK retardado. 450 En el segmento 32,, el cliente transmite 757A7%$ de datos, que el servidor reconoce en el segmento 33.. La situación es similar para los segmentos 34 y 35.. Los segmentos 36 y 37 provenientes del servidor, son reconocidos de manera acumulativa con el segmento 38 del cliente. En el segmento 39,, el cliente vuelve a enviar datos y el servidor los reconoce con el ACK retrasado del segmento 40.. Si repitiéramos mos la misma conexión, enviando al servidor los mismos requerimientos, el flujo no tendría por qué ser igual que el presentado, ya que la forma en que se transfieren los datos depende de la situación particular, particular de ambos extremos y de la red, en un momento dado. 12.6.2 .6.2 Intercambio de segmentos – Recepción de ACK duplicados En la Fig. 12.4 see presenta otro intercambio de datos entre otro cliente y el mismo servidor, donde se puede observar una situación de congestión, congestión, menos grave que el timeout, que se percibe por la recepción de ACK duplicados. Figura 12.4 – Situación de congestión. ACK duplicados. En el segmento 1,, el servidor transmite 53A7%$, luego 505 y 47A7%$ A7%$, en los segmentos 2 y 3 respectivamente. respectivamente En estos segmentos se observa el mismo número de ACK. Mediante el número de secuencia de estos segmentos, se puede inferir que el servidor ha 451 transmitido 56836 − 1A7%$, ya que el número de secuencia inicial ISN también cuenta, aunque en el segmento SYN no se envían datos. También, por el Número de ACK, se interpreta que el servidor ha recibido segmentos correctos y en orden hasta el byte 10987. En el segmento 4, el cliente reconoce todas las transmisiones previas, pero su número de secuencia es 2730 números mayor que lo que el servidor le ha reconocido. Esto se confirma en el segmento 5, cuando el servidor transmite 41A7%$, pero insiste con el mismo número de ACK que en los segmentos previos. En el segmento 6, el cliente tiene datos para transmitir y aprovecha para reconocer los datos del segmento previo transmitido por el servidor. La llegada del segmento 6 de 41A7%$ de datos del cliente, dispara del lado servidor un ACK sin datos, que repite el Número de ACK 10988. En su forma tradicional, cuando el protocolo TCP recibe datos correctamente pero fuera de orden, lo único que puede hacer es repetir el número de ACK correspondiente al último segmento recibido en orden y sin errores. Es lo que se denomina generación de ACK duplicados. No es una situación tan grave como un timeout, pero es un indicador de que un segmento pudo haberse perdido, aunque hay otros que siguen llegando correctamente pero fuera de orden. El aviso parece no ser suficiente para disparar una retransmisión, ya que el lado cliente sigue enviando nuevos datos, en los segmentos 8 y 9, primero 1460A7%$ y luego 24A7%$. La llegada de estos datos al servidor dispara dos nuevos ACK duplicados, se trata de los segmentos 9 y 10. Al recibirlos, el TCP del lado cliente considera necesaria la retransmisión del segmento con el número de secuencia esperado por el servidor, en el que carga 1460A7%$ de datos. Evidentemente, esta transmisión llena el hueco que existía en el buffer de recepción del protocolo TCP del lado servidor, pues este avanza el borde izquierdo de la ventana hasta el Número de ACK 15243 en el segmento 13. 12.6.3 Control de Flujo - Manejo de las ventanas de transmisión y recepción En la Fig. 12.5 se presenta otro intercambio cliente-servidor con el propósito de seguir la variación de las ventanas deslizantes de transmisión y recepción en entorno de flujo de grandes volúmenes de datos. En este ejemplo, el intercambio TCP comienza con el inicio de la conexión. El cliente envía un segmento SYN, con el valor de la opción MSS que indica que se encuentra en una LAN, un anuncio de factor de escalamiento de ventana de 8 y el aviso de que puede hacer reconocimiento de datos por bloque, SACK. El extremo TCP servidor puede manejar las mismas opciones, aunque el factor de escalamiento que usará es 6, según lo anuncia en el segmento 2. Como ambos entienden la opción de escalamiento de ventana, a partir de este momento cada segmento del lado cliente anunciará en el campo Ventana (win) un valor que deberá ser multiplicado por 2C = 256 para hallar el verdadero tamaño de la ventana. Del lado servidor, cada anuncio de ventana deberá ser multiplicado por 64 del lado cliente, para hallar el verdadero valor de la ventana de recepción del servidor. Se ha elegido presentar los campos 452 de win de los segmentos subsiguientes con el valor ya escalado, pero en realidad,, por ejemplo en el segmento 4,, el valor escrito en el campo win es 256, y en el segmento 5 es 10 108. En el segmento 4,, el cliente envía al servidor 513A7%$ de datos con Número de Secuencia 1.. La transmisión de este segmento se traduce en una ventana de transmisión (recuadro de línea punteado) con 513A7%$ almacenados a la espera de un ACK.. La ventana de recepción escalada anunciada por el cliente en este segmento es 65536A7%$. La transmisión del segmento 5 obedece al hecho de que el servidor ha recibido los datos correctamente, quedando la ventana de recepción (recuadro de línea línea llena) con el puntero de la izquierda apuntando al número 514,, el siguiente byte que espera recibir. El anuncio de la ventana escalada del servidor es 6912A7%$. Figura 12.5 – Control de Flujo por Ventanas Deslizantes. Luego el servidor transmite el segmento 6, con 352A7%$ de datos. Esto no modifica el valor de la ventana anunciada al otro extremo, pero sí modifica la situación de su propia ventana de transmisión, en este caso con 352A7%$ de datos a la espera ra de un ACK. La llegada 453 de este segmento, coloca el estado de la ventana de recepción del cliente como se ha supuesto en la figura. El segmento 7 es otra transmisión del servidor, de 15A7%$, que modifica el estado de la ventana de transmisión tal como se presenta en el recuadro punteado. Del lado cliente, si los datos llegan correctamente, se almacenan en la ventana de recepción, a la espera de ser entregados a la aplicación. La transmisión del ACK en el segmento 8, confirma la llegada correcta y vuelve a dejar libre el buffer de recepción del lado cliente. La recepción de este segmento permite al protocolo TCP del lado servidor, retirar los datos pendientes de su ventana de transmisión. A partir de este segmento la situación del par de ventanas de cada lado se mantiene estática porque ya no se intercambian más datos. En este ejemplo, se ha incluido el cierre de la conexión, para resaltar que tanto el segmento SYN, como el segmento FIN, utilizan un número de secuencia, a pesar de no transportar datos. 12.7 Aviso de ventana nula - Síndrome de la ventana tonta El anuncio de la ventana es lo que permite realizar el control de flujo por parte del receptor. Dado que TCP almacena los segmentos en el buffer de recepción, para subir a las aplicaciones aquellos que llegaron correctamente y en orden, si las aplicaciones no están ocupadas, inmediatamente leerán los datos del buffer, manteniéndose el anuncio de la ventana en un valor casi estático, constante. Otras veces, cuando las aplicaciones tienen tareas que cumplir, no pueden vaciar inmediatamente el buffer de recepción. En estos casos, se observarán anuncios de ventana más pequeños, pudiéndose llegar a una situación de aviso de ventana nulo. Un aviso de este tipo detendrá el flujo de datos transmitidos desde el otro extremo. La forma de reanudar la comunicación es enviando un segmento de actualización del estado de la ventana, una vez que se haya liberado espacio en el buffer de recepción. En general, luego de un aviso D# = 0, la actualización del tamaño de la ventana o window update, se realiza por medio de un segmento sin datos, o sea un segmento ACK, cuya transmisión no es confiable. El peligro de que dicho segmento se pierda podría conducir a una situación de punto muerto o deadlock, donde cada extremo espera que el otro realice alguna acción: el transmisor espera la actualización y el receptor espera que le envíen datos. Para evitar estas situaciones, TCP incluye un reloj persistente, conocido como timer persist, que dispara la transmisión de segmentos de sondeo de ventana, también conocidos como window probes, para obligar al extremo que anunció la ventana nula a realizar una actualización. La RFC 1122 aconseja disparar el mecanismo luego del primer RTO transcurrido desde el aviso D# = 0 y, a partir de allí, manejarlo con un mecanismo de backoff exponencial. No se define un límite máximo de segmentos de sondeo transmitidos, simplemente el mecanismo deja de funcionar al recibir una respuesta D# ≠ 0. 454 Los segmentos de sondeo se cargan con un byte de datos, para que su transmisión sea confiable, obligando al receptor a generar un aviso de ventana por medio de un segmento ACK. El dato se aceptará o no del lado receptor, dependiendo del estado del buffer de recepción. Por ejemplo, si el último ACK recibido con aviso de ventana D# = 0 transporta un Número de ACK 9034 , entonces el segmento de sondeo llevará un Número de Secuencia 9034, que es el que espera recibir el otro extremo. Puede cargar un byte de datos por que el protocolo permite que la numeración sobrepase el borde de la ventana cerrada. La respuesta del otro extremo, si la ventana continuara siendo nula, es un segmento ACK de número 9034, es decir que no se reconoce el byte de datos. Por este motivo el segmento window probe se sigue retransmitiendo. El aviso de ventana nula puede causar problemas si no se imponen ciertas condiciones. Si el receptor, ni bien sale de la condición de ventana cerrada, empieza a anunciar tamaños de ventana pequeños, y el transmisor aprovecha estos anuncios para transmitir datos inmediatamente, vuelve a llenar la ventana, provocando nuevos avisos de D# = 0. Esta situación se conoce como Síndrome de la Ventana Tonta (SWS, Silly Window Syndrome). Para evitarlo, basta con cumplir una serie de reglas, presentadas en la RFC 1122: • Regla 1: Los receptores no deben anunciar tamaños de ventana pequeños, aunque sean mayores que los advertidos previamente, hasta que la ventana pueda alcanzar el un valor que se fija en el mínimo entre el tamaño de un segmento completo, o sea el valor MSS, o la mitad del espacio del buffer de recepción. Esta regla se aplica cuando las aplicaciones liberan espacio del buffer de recepción, disparando actualizaciones, o en respuesta a window probes. • Regla 2: Para evitar el síndrome de la ventana tonta, los transmisores no deben enviar segmentos, al menos que se cumplan alguna de las siguientes condiciones: 1. Se puede enviar un segmento de tamaño MSS. Esta condición se incluye para evitar la ineficiencia debida al overhead, presente al transmitir segmentos pequeños. 2. Se puede enviar al menos la mitad del tamaño de ventana máximo anunciado por el receptor durante la conexión. Esta condición es para manejar la situación de aquellos dispositivos que anuncian tamaños de ventana de pocos bytes, tal vez menores que MSS. 3. Se puede transmitir todo lo que queda pendiente mientras no se está esperando ACK por ningún dato o el algoritmo de Nagle está deshabilitado para esta conexión. Esta última condición es aplicable al caso en que la aplicación del lado transmisor realice pequeñas escrituras. 12.8 Conexiones ociosas - Mecanismo Keepalive Se ha explicado hasta aquí la forma en que se establece una conexión, con su correspondiente reserva de recursos, algunas cuestiones relativas al intercambio de datos y los 455 aspectos relevantes del cierre de una conexión, ya sea que suceda de forma ordenada o desordenada, liberando los recursos pre-asignados. En este apartado se abordará la situación de aquellas conexiones que, una vez establecidas, permanecen ociosas, sin transmitir ni recibir datos. Esta situación podría deberse a una serie de razones no tan inusuales. Un cliente podría establecer una conexión TCP con una aplicación servidora, y luego el propio usuario retirarse de la máquina y dejar la conexión establecida sin intercambio de datos por un tiempo indeterminado. También, podría suceder que cayeran routers intermedios entre ambos extremos de la comunicación, condenando las conexiones a la inactividad, aunque se encuentren establecidas. Dependiendo de las circunstancias, podría ser útil que los extremos permanezcan conectados aunque tengan muy pocos datos para intercambiar. En otros casos, sería mejor terminar la conexión, para no desperdiciar recursos. Muchas implementaciones TCP proveen un método, denominado mantener vivo o keepalive, para probar si el otro extremo de la conexión se encuentra presente. El método lleva un reloj asociado, que se conoce con el mismo nombre, y que permite marcar tiempos que disparan el envío segmentos de sondeo al otro extremo, para comprobar si se encuentra presente. El problema con este esquema es que se pueden confundir situaciones de ociosidad legítimas con fallas transitorias de la red, terminando conexiones por motivos ajenos a las mismas. La controversia se extiende cuando se menciona que las aplicaciones deberían hacerse cargo de esta funcionalidad, aunque la contrapartida afirma que, si hubiese muchas aplicaciones que lo precisasen, lo más lógico sería que TCP la proveyera. Como la funcionalidad es opcional, existen algunos parámetros de configuración que se ajustan para controlar la ausencia de actividad de una conexión por algún período de tiempo, para disparar el mecanismo de sondeo. Un parámetro ajusta el período de repetición de los segmentos de sondeo, cuando no se recibe respuesta del otro extremo. También es posible configurar un número máximo de estos segmentos. Cuando se alcanza el límite sin respuestas, se considera el otro extremo inalcanzable y se finaliza la conexión. A diferencia de los segmentos de sondeo del reloj persistente, el número de secuencia de un sondeo keepalive es un número menos que el mayor número de ACK recibido desde el otro extremo. Al igual que los segmentos de sondeo del reloj persistente, estos segmentos pueden cargar un byte de datos. El dato en sí no es relevante para la conexión, ni queda sujeto al mecanismo tradicional de retransmisión, pero, de encontrarse presente y activo, el otro extremo contestará con un ACK. En cualquier caso, existen cuatro escenarios posibles: 456 1. El dispositivo en el otro extremo se encuentra activo y alcanzable. El protocolo TCP responderá con un ACK, reiniciando el reloj de keepalive en el extremo TCP que realiza el sondeo. 2. El dispositivo en el otro extremo ha caído y se encuentra en proceso de rearranque. No se recibirá respuesta por parte del protocolo TCP del otro extremo, por lo que se continuará con el sondeo keepalive, según los parámetros de expiración y número máximo de segmentos de prueba especificados. Si se alcanza este número y aún no se recibe respuesta, se da por terminada la conexión. La aplicación que realiza el sondeo puede recibir entonces un mensaje de “error por expiración”. Vale la pena aclarar que, cuando un dispositivo cae, no puede realizar el cierre, ni siquiera emitiendo un segmento RST. 3. El dispositivo en el otro extremo ha caído y re-arrancado. La respuesta al sondeo es un segmento con la bandera RST levantada, ya que no se reconoce la conexión que había estado establecida. Esta respuesta termina la conexión y se comunica a la aplicación a través de un mensaje que suele ser del tipo “conexión reiniciada por el par”. 4. El dispositivo en el otro extremo se encuentra activo pero es inalcanzable por problemas en la red. La situación no se podrá distinguir del caso 2, aunque podría llegar a recibirse un mensaje de error ICMP. La confusión entre el segundo y el cuarto escenario es lo que genera tanta controversia con respecto al uso de esta herramienta. En sistemas tipo Linux, los valores default del reloj de keepalive suelen ser de 2ℎ$, ajustándose en 75$%& el intervalo de sondeo y 9 segmentos como valor máximo de pruebas de sondeo. En Windows, en cambio, el intervalo se suele fijar en 1$%& y el valor máximo en 10 segmentos. El mecanismo de keepalive no se encuentra definido en la especificación de TCP pero, como algunos Sistemas Operativos lo incorporan, la RFC 1122 aclara que utilizarlo puede llevar a cerrar una conexión perfectamente establecida por falla en la Internet. También se critica en dicha RFC el consumo de ancho de banda de los mensajes en una conexión naturalmente ociosa y el costo en aquellos casos donde el cargo es por paquete transmitido. Bibliografía 1. RFC 793 “Transmission Control Protocol ˮ, September http://tools.ietf.org/html/rfc793 2. RFC 896 “Congestion Control in IP/TCP Internetworks”, January http://tools.ietf.org/html/rfc896 1981. 1984. 457 3. RFC 1122 “Requirements for Internet Hosts -- Communication Layersˮ, October 1989. http://tools.ietf.org/html/rfc1122 4. RFC 1323 “TCP Extensions for High Performanceˮ, May 1992. https://www.ietf.org/rfc/rfc1323.txt 5. RFC 6093 “On the Implementation of the TCP Urgent Mechanismˮ, January 2011. http://tools.ietf.org/html/rfc6093 6. RFC 6247 “Moving the Undeployed TCP Extensions RFC 1072, RFC 1106, RFC 1110, RFC 1145, RFC 1146, RFC 1379, RFC 1644, and RFC 1693 to Historic Status ˮ, May 2011. http://tools.ietf.org/html/rfc6247 7. RFC 6298 “Computing TCP´s Retransmission Timerˮ, June 2011. http://tools.ietf.org/html/rfc6298 8. Jacobson, Van, “Congestion Avoidance and Controlˮ, CM SIGCOMM Computer Communication Review. ACM, 1988. p. 314-329. 9. Karn, P. , C. Partridge, "Improving Round-Trip Time Estimates in Reliable Transport Protocols", SIGCOMM 87. http://ccr.sigcomm.org/archive/1995/jan95/ccr-9501partridge87.pdf 10. Kozierok, Charles M., “The TCP/IP Guideˮ. http://www.tcpipguide.com/free/t_toc.htm 11. Comer, Douglas, “Internetworking with TCP/IP: Principles, Protocols and Architecture v. 1ˮ. Pearson EducaƟon, 1995. 12. Stevens, W. Richard, “TCP/IP Illustrated, Vol. 1: The Protocols (Addison-Wesley Professional Computing Series) ˮ. Addison-Wesley, 1993. Problemas 1. ¿Cómo se establece el para una conexión TC? ¿Qué importancia tiene el Algoritmo de Karn? 2. Explique el concepto de re-empaquetado en TCP. 3. ¿Cuál es la característica del flujo de datos interactivos? ¿Para qué se utiliza el Algoritmo de Nagle? 4. ¿Cuál es el sentido del timer persist? ¿Qué relación existe entre el timer persist y el síndrome de la ventana tonta? 5. Mencione ventajas y desventajas asociadas con la implementación de un timer keepalive. 6. Sobre la siguiente captura de un segmento TCP, sabiendo que el cliente únicamente ha transferido 393 bytes al Servidor desde que comenzara la conexión, contestar: a) Nº de Secuencia del SYN inicial de Cliente a Servidor y Nº de Secuencia del SYN del Servidor al Cliente. c) Nº de Secuencia y Nº de ACK del segmento con los 393 bytes de Cliente a Servidor. d) Sabiendo que en el SYN inicial de Cliente a Servidor el campo de opciones era: < Maximum segment size: 1460 bytes, NOP, Window scale: 1, NOP, NOP, SACK permitted >, determine el verdadero valor de la ventana anunciada en el segmento capturado. 458 Transmission Control Protocol, Source port: http (80) Destination port: 1543 (1543) Sequence number: 2976738361 Acknowledgement number: 1544685068 Header length: 20 bytes Flags: 0x0010 (ACK) 0... .... = Congestion Window Reduced (CWR): Not set .0.. .... = ECN-Echo: Not set ..0. .... = Urgent: Not set ...1 .... = Acknowledgment: Set .... 0... = Push: Not set .... .0.. = Reset: Not set .... ..0. = Syn: Not set .... ...0 = Fin: Not set Window size: 6432 Checksum: 0xfc01 (correct). 459