Nagle algoritmo y TCP socket opción TCP_CORK

algoritmo de Nagle

algoritmo Nagle propuesto en 1984 por el John Nagle, este algoritmo puede reducir el número de la red de pequeñas y medianas de paquetes, reduciendo de ese modo el grado de congestión de la red. Un ejemplo común es la aplicación Telnet, cada usuario envía una pulsación de tecla de la consola de paquetes, este paquete por lo general contiene 41 bytes, sin embargo, sólo un byte es una carga útil, los 40 bytes restantes son de cabeza, si cada pulsación de tecla envía un paquete, causará una enorme sobrecarga.

Para reducir esta sobrecarga, Nagle algoritmo de señalar que cuando TCP envía un segmento pequeño (menos de SMS), debe esperar a recibir ACK de cada uno, con el fin de continuar enviando otro segmento pequeño. Luego de espera para el proceso (un tiempo RTT), un TCP de datos puede transmitir tanto como sea posible para ser recogidos juntos, reduciendo así el número del segmento que va a transmitirse.

Por defecto, TCP abrió el algoritmo de Nagle, sin embargo Nagle algoritmo no es una panacea, además de aumentar los datos de envío latencia TCP. En algunos requisitos de las aplicaciones de baja latencia (como aplicaciones de mensajería instantánea), es necesario deshabilitar el algoritmo de Nagle:

int optval = 1;
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
ACK retardado

Nagle algoritmo de TCP y el DelayedPause ACK tienen el mismo propósito, la DelayedPause ACK se entiende bien que, cuando los datos TCP recibidos, y ACK no se envía inmediatamente a la otra, por el contrario, se espera a que los datos de capa de aplicación a los datos junto con ACK y enviar (esperar hasta 40 ms en Linux).

Sabemos, Nagle algoritmo añade datos de transmisión TCP latencia, sin embargo, en algunos casos, ACK retardado en magnificar este retraso. Un ejemplo común de un protocolo HTTP de POST cliente, en primer vistazo al código de cliente:

write(http_request_header);
write(http_request_body);
// get response from server ...

El cliente llama dos veces de escritura () para enviar una petición HTTP POST al servidor necesita llamar leído dos veces () lee la solicitud HTTP del cliente:

http_request_header = read(...);
http_request_body = read(...);
// write response to client ...

En general, HTTP encabezado de la solicitud y el cuerpo son un segmento pequeño, pero el algoritmo de Nagle TCP activadas por defecto, por lo que el cliente envía una solicitud después de la cabecera, si no se ha recibido ACK, no se puede enviar el cuerpo.

Aquí Insertar imagen Descripción
cabecera del servidor después de la recepción de la solicitud, ya que el cuerpo aún no ha recibido una solicitud, no puede producir una respuesta inmediata al cliente HTTP, lo que llevó a la http_request_header de ACK probablemente retrasar 40 ms antes de enviar.

Para evitar este retraso, que tenemos que hacer dos cosas:

  • TCP_NODELAY opción set.
  • Los dos escritura cliente () se fusionaron en uno solo, para evitar lado del servicio de ACK con retraso.
Scatter-Gather I / O

escritura () es responsable de los datos de las aplicaciones se escriben en el búfer en el búfer del núcleo, la operación de combinación de dos de escritura (), una práctica común es asignar un búfer relativamente grande, seguido por dos búfer menor copiado de forma secuencial a la zona de datos de este gran buffer, la última llamada de escritura () de una sola escritura esta gran búfer de datos. Sin embargo, este enfoque no ha traído pequeño coste, tiempo y establecimiento de memoria dos veces (operación) operación de asignación de memoria. Afortunadamente, Linux proporciona la función de writev (), que puede ser algunos datos de memoria intermedia discreta se escribe en el núcleo.

struct iovec iov[2];
iov[0].iov_base = http_request_header;
iov[0].iov_len = sizeof(http_request_header);
iov[1].iov_base = http_request_body;
iov[1].iov_len = sizeof(http_request_body);
ssize_t nwritten = writev(fd, iov, 2);
TCP_CORK

La mayor parte de servidor Web Para mejorar el rendimiento, los datos no se envía directamente de escritura (), es un ejemplo típico, el tiempo de respuesta de servidor Web para solicitudes de los clientes, se necesita enviar un encabezado de respuesta HTTP, y luego enviar el contenido de una página web, y existe el contenido de la página en el disco, con el fin de reducir la sobrecarga de copiar los datos, por lo general mediante el sendfile () para enviar el contenido de la página, en este caso, la aplicación en modo usuario no necesita asignar memoria para almacenar el contenido de la página.

const char *filename = "index.html";
fd = open(filename, O_RDONLY)
write(http_resp_header);
sendfile(sockfd, fd, &off, len);

Para enviar la respuesta HTTP, servidor de llamada escritura una sola vez () y una vez sendfile (), en el caso de TCP_NODELAY abierta, lo que llevará a cabo al menos dos Enviar segmento TCP. Pero más datos cuando la página es muy pequeña, en este caso, de escritura () envía un segmento, sendfile () enviará un segmento, entonces no hay manera de combinar los dos segmentos volvió a enviar que?

Para resolver este problema, la opción de ofertas TCP_CORK Linux, si esta opción está activada en un socket TCP, que es equivalente a la exportación de esta toma para conectar el enchufe en la toma de datos escritos serán reunidos. A pesar de que el enchufe del enchufe, pero la tiene que enviar segmento, de lo contrario los datos se llenarán de toda la memoria intermedia de envío TCP, a continuación, conecte cuando se abre? Las siguientes condiciones harán que el enchufe a abierta, por lo que puede continuar enviando segmento TCP a cabo.

  • programa TCP_CORK desactivada esta opción.
  • datos de socket agregado es mayor que un tamaño de la MSS.
  • Desde el tapón tapón escrito al primer byte, que ha pasado de 200 ms.
  • socket estaba cerrado.

Cualquiera de las anteriores condiciones se satisfacen una vez, se enviarán los datos TCP. Para el servidor, la respuesta HTTP se envía únicamente para enviar lo menos posible del segmento, al tiempo que garantiza una baja latencia, necesita cancelar explícitamente el ajuste después de escribir opción TCP_CORK de datos para enviar datos a cabo de inmediato:

int state = 1;
setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
write(http_resp_header);
sendfile(sockfd, fd, &off, len);
state = 0;
setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));

Publicados 374 artículos originales · elogios ganado 14 · Vistas de 100.000 +

Supongo que te gusta

Origin blog.csdn.net/LU_ZHAO/article/details/105377741
Recomendado
Clasificación