¿Hay alguna manera de vaciar un zócalo POSIX?

10 minutos de lectura

avatar de usuario
gordon wrigley

¿Existe una llamada estándar para vaciar el lado de transmisión de un conector POSIX hasta el extremo remoto o es necesario implementarlo como parte del protocolo de nivel de usuario? Miré alrededor de los encabezados habituales, pero no pude encontrar nada.

avatar de usuario
fantastoria

¿Qué hay de configurar TCP_NODELAY y luego restablecerlo? Probablemente podría hacerse justo antes de enviar datos importantes, o cuando hayamos terminado de enviar un mensaje.

send(sock, "notimportant", ...);
send(sock, "notimportant", ...);
send(sock, "notimportant", ...);
int flag = 1; 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
send(sock, "important data or end of the current message", ...);
flag = 0; 
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));

Como dice la página man de linux

TCP_NODELAY… establecer esta opción fuerza un vaciado explícito de la salida pendiente…

Así que probablemente sería mejor configurarlo después del mensaje, pero no estoy seguro de cómo funciona en otros sistemas.

  • Esto debería funcionar con Linux al menos; cuando configura TCP_NODELAY, vacía el búfer actual, que debería, según los comentarios de la fuente, incluso vaciar cuando se configura TCP_CORK.

    – Stefan

    25 de mayo de 2013 a las 13:29

  • Confirmo que funciona. Prefiero establecer y restablecer TCP_DELAY después de enviar los “datos importantes o el final del mensaje actual” porque permite colocar estas cosas dentro de un método de conexión de descarga.

    – promomonet

    20/03/2014 a las 21:33

  • Describe una situación en la que los mensajes “no importantes” se mezclan con mensajes que deben enviarse lo antes posible. Para esta situación, supongo que su solución es una buena manera de eludir el retraso que podría haber introducido Nagle. Sin embargo, si no envía varios mensajes sino un mensaje compuesto, debe enviarlo con un solo mensaje. send() ¡llamada! Es porque incluso con Nagle, el primer paquete se envía de inmediato. Solo los posteriores se retrasan, y se retrasan solo hasta que el servidor reconoce o responde. Así que empaca “todo” en el primero send().

    – hagello

    24 de junio de 2018 a las 12:09


  • Es cierto, pero en este caso, no sabemos qué tan grandes son los datos no importantes, ni si hubo demoras entre envíos individuales. El problema surge cuando los datos se envían en una dirección. Por ejemplo, trabajo como un proxy: reenvío todo lo que recibo, esa red lo enviará de manera óptima, por lo que no me importa. Pero luego viene un paquete importante, que quiero enviar lo antes posible. Que es lo que yo entiendo por enrojecimiento.

    – Fantasía

    18 de marzo de 2019 a las 14:59


avatar de usuario
caos

Para sockets de dominio Unix, puede usar fflush(), pero creo que probablemente te refieres a enchufes de red. Realmente no existe un concepto de vaciarlos. Las cosas más cercanas son:

  1. Al final de su sesión, llamando shutdown(sock, SHUT_WR) para cerrar escribe en el zócalo.

  2. En sockets TCP, deshabilitar el algoritmo Nagle con sockopt TCP_NODELAYque generalmente es una idea terrible que no hará de manera confiable lo que desea, incluso si parece resolverlo en la investigación inicial.

Es muy probable que manejar cualquier problema que requiera un ‘vaciado’ en el nivel del protocolo de usuario sea lo correcto.

  • No veo ninguna razón por la que deshabilitar el algoritmo de Nagle “generalmente sea una idea terrible”. Si sabe lo que hace, hay muchas situaciones de protocolo de aplicación en las que deshabilitar Nagle es exactamente lo que desea hacer. Sospecho que no ha tenido una situación en la que realmente necesitaba hacer eso o no entiende lo que realmente hace. En otras palabras, esta característica está ahí por una razón y también se puede deshabilitar por una muy buena razón.

    – Jeff alto

    13 de mayo de 2009 a las 1:21

  • tendrás que #include <linux/tcp.h> o lo que sea que proporcione el archivo de inclusión TCP_NODELAY en su sistema (pruebe fgrep -r 'define TCP_NODELAY' /usr/include).

    – caos

    1 de febrero de 2010 a las 17:20

  • Nagle podría haber sido algo maravilloso si hubiera una descarga de TCP. Dado que puede optimizar su tamaño de búfer al tamaño del segmento actual. Si deshabilita nagle, tiene un búfer propio que no está sincronizado con el tamaño del segmento, por lo que enviará paquetes medio llenos a través de la red…

    – mmmmmmmm

    18 de noviembre de 2010 a las 9:13


  • fflush no tiene nada que ver con el problema, incluso para los sockets de dominio de Unix. Solo es relevante si ha envuelto su socket con un FILE vía fdopen

    – R.. GitHub DEJA DE AYUDAR A ICE

    18 de noviembre de 2011 a las 3:41

  • Lo que hago es habilitar Nagle, escribir tantos bytes (usando E/S sin bloqueo) como pueda en el socket (es decir, hasta que me quede sin bytes para enviar, o la llamada send() devuelve EWOULDBLOCK, lo que ocurra primero) y luego deshabilite Nagle nuevamente. Esto parece funcionar bien (es decir, obtengo paquetes de baja latencia Y de tamaño completo cuando es posible)

    –Jeremy Friesner

    25 de abril de 2013 a las 14:46


avatar de usuario
hagello

En RFC 1122, el nombre de lo que está buscando es “PUSH”. Sin embargo, no parece haber una implementación API de TCP relevante que implemente “PUSH”. Por desgracia, no hay suerte.

Algunas respuestas y comentarios tratan sobre el algoritmo de Nagle. La mayoría de ellos parecen suponer que el algoritmo de Nagle retrasa todos y cada uno de los cada enviar. Esta suposición no es correcta. Nagle retrasa el envío solo cuando al menos uno de los paquetes anteriores aún no ha sido reconocido (http://www.unixguide.net/network/socketfaq/2.11.shtml).

Para decirlo de otra manera: TCP enviará el primero paquete (de una fila de paquetes) inmediatamente. Solo si la conexión es lenta y su computadora no recibe un reconocimiento oportuno, Nagle retrasará el envío datos posteriores hasta que (lo que ocurra primero)

  • se alcanza un tiempo muerto o
  • el último paquete no reconocido es reconocido o
  • su búfer de envío está lleno o
  • desactivas Nagle o
  • cierras la dirección de envío de tu conexión

Una buena mitigación es evitar el negocio de datos posteriores tan lejos como sea posible. Esto significa: Si su aplicación llama send() más de una vez para transmitir una sola solicitud compuesta, intente reescribir su aplicación. Ensamble la solicitud compuesta en el espacio del usuario, luego llame send(). Una vez. Esto también ahorra cambios de contexto (mucho más costosos que la mayoría de las operaciones en el espacio del usuario).

Además, cuando el búfer de envío contiene suficientes datos para llenar el tamaño máximo de un paquete de red, Nagle tampoco se demora. Esto significa: si el último paquete que envía es lo suficientemente grande como para llenar su búfer de envío, TCP enviará sus datos lo antes posible, pase lo que pase.

Para resumir: Nagle no es el enfoque de fuerza bruta para reducir la fragmentación de paquetes que algunos podrían considerar que es. Al contrario: A mí me parece un enfoque útil, dinámico y eficaz para mantener tanto un buen tiempo de respuesta como una buena relación entre datos de usuario y datos de cabecera. Dicho esto, debes saber cómo manejarlo de manera eficiente.

avatar de usuario
jeff alto

No hay forma de que yo sepa en la interfaz de socket TCP/IP estándar para vaciar los datos “hasta el extremo remoto” y asegurarse de que realmente se haya reconocido.

En términos generales, si su protocolo necesita una transferencia de datos en “tiempo real”, generalmente lo mejor que puede hacer es configurar el setsockopt() de TCP_NODELAY. Esto deshabilita el algoritmo de Nagle en la pila de protocolos y write() o send() en el socket se asigna más directamente a los envíos a la red… en lugar de implementar retenciones de envío esperando que haya más bytes disponibles y usando todos los Temporizadores de nivel de TCP para decidir cuándo enviar. NOTA: Desactivar Nagle no desactiva la ventana deslizante de TCP ni nada, por lo que siempre es seguro hacerlo… pero si no necesita las propiedades de “tiempo real”, la sobrecarga de paquetes puede aumentar bastante.

Más allá de eso, si los mecanismos de socket TCP normales no se ajustan a su aplicación, generalmente debe recurrir al uso de UDP y crear sus propias funciones de protocolo en las propiedades básicas de envío/recepción de UDP. Esto es muy común cuando su protocolo tiene necesidades especiales, pero no subestime la complejidad de hacerlo bien y lograr que todo sea estable y funcionalmente correcto en todas las aplicaciones, excepto en las relativamente simples. Como punto de partida, un estudio exhaustivo de las características de diseño de TCP arrojará luz sobre muchas de las cuestiones que deben tenerse en cuenta.

Creo que sería extremadamente difícil, si no imposible, implementarlo correctamente. ¿Cuál es el significado de “descarga” en este contexto? Bytes transmitidos a la red? ¿Bytes reconocidos por la pila TCP del receptor? ¿Bytes pasados ​​a la aplicación de modo de usuario del receptor? ¿Bytes completamente procesados ​​por la aplicación en modo usuario?

Parece que tienes que hacerlo en el nivel de la aplicación…

  • Nagle = no enviar por cable inmediatamente. No Nagle = enviar por cable de inmediato. La opción intermedia está fija en la cara de todos: no envíe al cable inmediatamente (Nagle) excepto cuando digo Enviar ahora (el escurridizo TCP Flush).

    – Román Starkov

    17 de julio de 2011 a las 21:02

  • @romkyns Sin embargo, el envío real () es asíncrono con respecto al envío, independientemente del estado de Nagle.

    – usuario207421

    18/07/2014 a las 20:34

avatar de usuario
norman ramsey

TCP proporciona solo la entrega de mejor esfuerzo, por lo que el hecho de que todos los bytes salgan de la Máquina A es asíncrono con el hecho de que todos hayan sido recibidos en la Máquina B. La pila de protocolos TCP/IP lo sabe, por supuesto, pero no conozco ninguno. forma de interrogar a la pila TCP para averiguar si todo lo enviado ha sido reconocido.

Con mucho, la forma más fácil de manejar la pregunta es a nivel de aplicación. Abra un segundo socket TCP para que actúe como un canal trasero y haga que el socio remoto le envíe un reconocimiento de que ha recibido la información que desea. Costará el doble, pero será completamente portátil y le ahorrará horas de tiempo de programación.

  • Nagle = no enviar por cable inmediatamente. No Nagle = enviar por cable de inmediato. La opción intermedia está fija en la cara de todos: no envíe al cable inmediatamente (Nagle) excepto cuando digo Enviar ahora (el escurridizo TCP Flush).

    – Román Starkov

    17 de julio de 2011 a las 21:02

  • @romkyns Sin embargo, el envío real () es asíncrono con respecto al envío, independientemente del estado de Nagle.

    – usuario207421

    18/07/2014 a las 20:34

avatar de usuario
usuario1402866

Puede configurar la opción tcp SO_LINGER para establecer un cierto tiempo de espera y luego cerrar el socket para asegurarse de que se hayan enviado todos los datos (o detectar fallas al hacerlo) al cerrar una conexión. Aparte de eso, TCP es un protocolo de “mejor esfuerzo” y no proporciona ninguna garantía real de que los datos lleguen a su destino (en contraste con lo que algunos parecen creer), simplemente hace todo lo posible para que se entreguen. en el orden correcto y tan pronto como sea posible.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad