program - socket c
¿Hay alguna manera de purgar un socket POSIX? (8)
¿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
¿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.
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 pila 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 ...
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.
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 pila 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 aumentar 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.
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.
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 pila del protocolo TCP / IP lo sabe, por supuesto, pero no conozco ningún 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 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 programación.
Use fsync ():
sock_fd es un descriptor de archivo entero de la llamada socket (..., ...)
fsync (sock_fd);
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:
Al final de la sesión,
shutdown(sock, SHUT_WR)
llamadashutdown(sock, SHUT_WR)
para cerrar las escrituras en el socket.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.