¿Hay alguna manera de purgar un socket POSIX?

¿Hay una llamada estándar para enjuagar el lado de transmisión de un socket 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.

Para los sockets de dominio Unix, puedes usar fflush() , pero creo que probablemente te refieres a los sockets de red. Realmente no hay un concepto de enjuagarlos. Las cosas más cercanas son:

  1. Al final de la sesión, shutdown(sock, SHUT_WR) llamada shutdown(sock, SHUT_WR) para cerrar las escrituras en el socket.

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

Es muy probable que el manejo de cualquier problema requiera una “descarga” en el nivel de protocolo del usuario sea lo correcto.

¿Qué hay de configurar TCP_NODELAY y luego reiniciarlo? 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 linux man pages

TCP_NODELAY … al configurar esta opción se fuerza un flujo explícito de salida pendiente …

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

No hay forma de que sepa en la interfaz estándar de socket TCP / IP para vaciar los datos “hasta el final remoto” y asegurarse de que hayan sido reconocidos.

En términos generales, si su protocolo necesita transferencia de datos en “tiempo real”, generalmente lo mejor es configurar setsockopt() de TCP_NODELAY . Esto inhabilita el algoritmo de Nagle en la stack de protocolos y write () o send () en el socket mapas más directamente para enviar a la red … en lugar de implementar envíos de espera esperando a que haya más bytes disponibles y usando todo el Temporizadores de nivel 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 del paquete puede boost bastante.

Más allá de eso, si los mecanismos de socket TCP normales no se ajustan a su aplicación, generalmente necesita recurrir a UDP y construir sus propias características 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 muchos de los problemas que deben considerarse.

En RFC 1122, el nombre de lo que estás buscando es “PUSH”. Aunque no conozco ninguna API TCP que implemente “PUSH”.

Algunas respuestas y comentarios se refieren al algoritmo de Nagle. La mayoría de ellos parecen suponer que el algoritmo de Nagle retrasa cada envío. Esta suposición no es correcta. Nagle retrasa el envío solo cuando un paquete anterior aún no ha sido reconocido ( http://www.unixguide.net/network/socketfaq/2.11.shtml ).

Para simplificarlo un poco: TCP intenta enviar el primer paquete (de una fila de paquetes) inmediatamente, pero retrasa los paquetes subsiguientes hasta que se alcanza el tiempo de espera o se confirma el primer paquete, lo que ocurra primero.

Una solución es evitar estos “paquetes subsiguientes”. Si su aplicación llama a send () más de una vez para transmitir una única solicitud compuesta, intente reescribir su aplicación. Ensamble la solicitud en el espacio de usuario, luego llame a send() . Una vez.

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 demora ninguno. Esto significa que Nagle no (realmente) retrasa un envío masivo, incluso si send() los datos masivos en pequeños fragmentos.

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

Parece que debes hacerlo a nivel de aplicación …

TCP da solo el mejor esfuerzo de entrega, por lo que el hecho de tener todos los bytes salidos de la Máquina A es asíncrono y todos han sido recibidos en la Máquina B. La stack del protocolo TCP / IP lo sabe, por supuesto, pero no conozco ningún forma de interrogar a la stack 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 actuar como un canal secundario y haga que el socio remoto le envíe un reconocimiento de que ha recibido la información que desea. Costará doble pero será completamente portátil y le ahorrará horas de tiempo de progtwigción.

Puede configurar la opción tcp SO_LINGER para establecer un tiempo de espera determinado y luego cerrar el zócalo para asegurarse de que se han enviado todos los datos (o detectar la falla 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 realmente al destino (en contraste con lo que algunos parecen creer), simplemente hace lo posible para que se entregue. en el orden correcto y tan pronto como sea posible.

Use fsync ():

sock_fd es un descriptor de archivo entero de la llamada socket (…, …)

fsync (sock_fd);