tagger tag puddletag picard musicbrainz mp3tag mac kid3 editar easytag linux tcp network-programming

tag - Control de aplicaciones de retransmisión de TCP en Linux



puddletag (5)

Después de pensar (y buscar en Google), llegué a la conclusión de que no se puede cambiar el valor de tcp_retries1 y tcp_retries2 para un solo socket a menos que aplique algún tipo de parche al kernel. ¿Es eso factible para ti?

De otra manera, podría usar la opción de socket TCP_KEEPALIVE cuyo propósito es verificar si una conexión está todavía activa (me parece que eso es exactamente lo que está tratando de lograr, por lo que tiene sentido). ¡Preste atención al hecho de que necesita ajustar un poco su parámetro predeterminado, porque el valor predeterminado es desconectarse después de aproximadamente 2 horas!

Para el impaciente:

¿Cómo cambiar el valor de /proc/sys/net/ipv4/tcp_retries2 para una sola conexión en Linux, usando setsockopt() , ioctl() o tal, o es posible?

Decription más largo:

Estoy desarrollando una aplicación que utiliza solicitudes HTTP de sondeo largo. En el lado del servidor, debe conocerse cuando el cliente ha cerrado la conexión. La precisión no es crítica, pero ciertamente no puede ser de 15 minutos. Más cerca de un minuto lo haría bien.

Para aquellos que no están familiarizados con el concepto, una solicitud HTTP de sondeo largo funciona así:

  • El cliente envía una solicitud.
  • El servidor responde con encabezados HTTP, pero deja la respuesta abierta. Se utiliza la codificación de transferencia fragmentada, lo que permite que el servidor envíe bits de datos a medida que estén disponibles.
  • Cuando se envían todos los datos, el servidor envía un "fragmento de cierre" para indicar que la respuesta está completa.

En mi aplicación, el servidor envía "latidos" al cliente de vez en cuando (30 segundos de forma predeterminada). Un latido es solo un carácter de nueva línea que se envía como un fragmento de respuesta. Esto está destinado a mantener la línea ocupada para que notifiquemos la pérdida de conexión.

No hay problema cuando el cliente se apaga correctamente. Pero cuando se apaga con fuerza (la máquina cliente pierde energía, por ejemplo), no se envía un reinicio de TCP. En este caso, el servidor envía un latido, que el cliente no ACK. Después de esto, el servidor continúa retransmitiendo el paquete durante aproximadamente 15 minutos después de darse por vencido y reportar el fallo a la capa de aplicación (nuestro servidor HTTP). Y 15 minutos es una espera demasiado larga en mi caso.

Puedo controlar el tiempo de retransmisión escribiendo en los siguientes archivos en /proc/sys/net/ipv4/ :

tcp_retries1 - INTEGER This value influences the time, after which TCP decides, that something is wrong due to unacknowledged RTO retransmissions, and reports this suspicion to the network layer. See tcp_retries2 for more details. RFC 1122 recommends at least 3 retransmissions, which is the default. tcp_retries2 - INTEGER This value influences the timeout of an alive TCP connection, when RTO retransmissions remain unacknowledged. Given a value of N, a hypothetical TCP connection following exponential backoff with an initial RTO of TCP_RTO_MIN would retransmit N times before killing the connection at the (N+1)th RTO. The default value of 15 yields a hypothetical timeout of 924.6 seconds and is a lower bound for the effective timeout. TCP will effectively time out at the first RTO which exceeds the hypothetical timeout. RFC 1122 recommends at least 100 seconds for the timeout, which corresponds to a value of at least 8.

El valor predeterminado de tcp_retries2 es de hecho 8, y mi experiencia de 15 minutos (900 segundos) de retransmisión está en línea con la documentación del kernel citada anteriormente.

Si cambio el valor de tcp_retries2 a 5 por ejemplo, la conexión muere mucho más rápido. Pero configurarlo de esta manera afecta a todas las conexiones en el sistema, y ​​realmente me gustaría configurarlo solo para esta conexión de sondeo largo.

Una cita de RFC 1122:

4.2.3.5 TCP Connection Failures Excessive retransmission of the same segment by TCP indicates some failure of the remote host or the Internet path. This failure may be of short or long duration. The following procedure MUST be used to handle excessive retransmissions of data segments [IP:11]: (a) There are two thresholds R1 and R2 measuring the amount of retransmission that has occurred for the same segment. R1 and R2 might be measured in time units or as a count of retransmissions. (b) When the number of transmissions of the same segment reaches or exceeds threshold R1, pass negative advice (see Section 3.3.1.4) to the IP layer, to trigger dead-gateway diagnosis. (c) When the number of transmissions of the same segment reaches a threshold R2 greater than R1, close the connection. (d) An application MUST be able to set the value for R2 for a particular connection. For example, an interactive application might set R2 to "infinity," giving the user control over when to disconnect. (e) TCP SHOULD inform the application of the delivery problem (unless such information has been disabled by the application; see Section 4.2.4.1), when R1 is reached and before R2. This will allow a remote login (User Telnet) application program to inform the user, for example.

Me parece que tcp_retries1 y tcp_retries2 en Linux corresponden a R1 y R2 en el RFC. El RFC indica claramente (en el artículo d) que una implementación conforme DEBE permitir el establecimiento del valor de R2 , pero no he encontrado manera de hacerlo utilizando setsockopt() , ioctl() o setsockopt() .

Otra opción sería obtener una notificación cuando se supere R1 (artículo e). Sin embargo, esto no es tan bueno como configurar R2 , ya que creo que R1 se alcanza muy pronto (en unos segundos), y el valor de R1 no se puede establecer por conexión, o al menos el RFC no lo requiere.


Esto es para mi entendimiento. tcp_retries2 es el número de retransmisión permitido por el sistema antes de cancelar la conexión. Por lo tanto, si queremos cambiar el valor predeterminado de tcp_retries2 usando TCP_USER_TIMEOUT que especifica la cantidad máxima de tiempo que los datos transmitidos pueden permanecer sin ser reconocidos, tenemos que aumentar el valor de TCP_USER_TIMEOUT ¿verdad?

En ese caso, la concesión esperará más tiempo y no retransmitirá el paquete de datos. Por favor corrígeme, si algo está mal.


Parece que esto fue agregado en el Kernel 2.6.37. Cometer diff desde el núcleo Git y Extracto del registro de cambios a continuación;

cometer dca43c75e7e545694a9dd6288553f55c53e2a3a3 Autor: Jerry Chu Fecha: viernes 27 de agosto 19:13:28 2010 +0000

tcp: Add TCP_USER_TIMEOUT socket option. This patch provides a "user timeout" support as described in RFC793. The socket option is also needed for the the local half of RFC5482 "TCP User Timeout Option". TCP_USER_TIMEOUT is a TCP level socket option that takes an unsigned int, when > 0, to specify the maximum amount of time in ms that transmitted data may remain unacknowledged before TCP will forcefully close the corresponding connection and return ETIMEDOUT to the application. If 0 is given, TCP will continue to use the system default. Increasing the user timeouts allows a TCP connection to survive extended periods without end-to-end connectivity. Decreasing the user timeouts allows applications to "fail fast" if so desired. Otherwise it may take upto 20 minutes with the current system defaults in a normal WAN environment. The socket option can be made during any state of a TCP connection, but is only effective during the synchronized states of a connection (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, or LAST-ACK). Moreover, when used with the TCP keepalive (SO_KEEPALIVE) option, TCP_USER_TIMEOUT will overtake keepalive to determine when to close a connection due to keepalive failure. The option does not change in anyway when TCP retransmits a packet, nor when a keepalive probe will be sent. This option, like many others, will be inherited by an acceptor from its listener. Signed-off-by: H.K. Jerry Chu <[email protected]> Signed-off-by: David S. Miller <[email protected]>


Sugiero que si la opción de socket TCP_USER_TIMEOUT descrita por Kimvais está disponible, use eso. En los kernels anteriores donde la opción de socket no está presente, puede llamar repetidamente al ioctl() SIOCOUTQ para determinar el tamaño de la cola de envío del socket. Si la cola de envío no disminuye durante su período de espera, eso indica que no se han realizado ACK. Recibido y puedes cerrar el zócalo.


int name[] = {CTL_NET, NET_IPV4, NET_IPV4_TCP_RETRIES2}; long value = 0; size_t size = sizeof(value); if(!sysctl(name, sizeof(name)/sizeof(name[0]), &value, &size, NULL, 0) { value // It contains current value from /proc/sys/net/ipv4/tcp_retries2 } value = ... // Change value if it needed if(!sysctl(name, sizeof(name)/sizeof(name[0]), NULL, NULL, &value, size) { // Value in /proc/sys/net/ipv4/tcp_retries2 changed successfully }

De manera programática usando C. Funciona al menos en Ubuntu. Pero (de acuerdo con el código y las variables del sistema) parece que influye en todas las conexiones TCP en el sistema, no solo en una única conexión.