que - socket udp java
MĂșltiple sendto() usando socket UDP (7)
Debe implementar acuses de recibo y retransmisión. Requerir, por ejemplo, acks para cada N paquetes y mantener N paquetes en el buffer de retransmisión.
( Tal vez puedas obtener algunas ideas de rudp , o implementar Il sobre UDP)
UDP no es confiable, y tampoco proporciona control de flujo. La historia corta es que perderás paquetes de vez en cuando, especialmente si envías datos rápidamente, el núcleo o cualquier enrutador / conmutador entre ellos arrojarán paquetes si no hay suficiente espacio, y hay poca magia que puedas emplear para no hacer eso ocurrir.
Tengo un software de red que usa UDP para comunicarse con otras instancias del mismo programa. Por diferentes razones, debo usar UDP aquí.
Hace poco tuve problemas para enviar grandes cantidades de datos a través de UDP y tuve que implementar un sistema de fragmentación para dividir mis mensajes en pequeños fragmentos de datos. Hasta ahora, funcionó bien, pero ahora tengo un problema cuando tengo que enviar muchos fragmentos de datos.
Tengo el siguiente algoritmo:
- Divida el mensaje en pequeños fragmentos de datos (alrededor de 1500 bytes)
- Itere sobre la lista de fragmentos de datos y para cada uno, envíela usando
sendto()
Sin embargo, cuando envío una gran cantidad de fragmentos de datos, el receptor solo recibe los primeros 6 mensajes. A veces falla el sexto y recibe el séptimo. Depende.
De todos modos, sendto()
siempre indica éxito. Esto siempre sucede cuando pruebo mi software a través de una interfaz loopback (127.0.0.1) pero nunca a través de mi red LAN.
Si agrego algo como std::cout << "test" << std::endl;
entre el sendto()
entonces se recibe cada fotograma.
Soy consciente de que el UDP permite la pérdida de paquetes y que mis cuadros pueden perderse por muchas razones y supongo que tiene que ver con la tasa a la que estoy enviando los fragmentos de datos.
¿Cuál sería el enfoque correcto aquí?
- Implementar algún mecanismo de reconocimiento (al igual que TCP) parece excesivo.
- Agregar un tiempo de espera arbitrario entre
sendto()
es feo y probablemente disminuirá el rendimiento. - ¿Aumenta (si es posible) el buffer interno del receptor UDP? Ni siquiera sé si esto es posible.
- Algo más ?
Realmente necesito tus consejos aquí.
Muchas gracias.
Información adicional según lo solicitado
La razón por la que debo usar UDP es porque tengo varias restricciones:
- TCP no funciona bien con NAT transversal (al menos sin una configuración específica)
- Algunos mensajes pueden perderse. Algunos otros no pueden.
- El orden de entrega del mensaje no importa.
Implementar un mecanismo de reconocimiento parece exactamente lo que necesita hacer. De esta forma, puede asegurarse de que no más de N paquetes estén "en vuelo" a la vez, y puede retransmitir paquetes que no han sido reconocidos por mucho tiempo.
Si está perdiendo paquetes en la interfaz de bucle invertido después de enviar solo 6 o 7 paquetes, entonces parece que su búfer de recepción es demasiado pequeño. Puede aumentar el tamaño con setsockopt usando la opción SO_RCVBUF. Sin embargo, si está enviando 1500 bytes, entonces si este es realmente el problema, significa que el buffer de recepción es solo de aproximadamente 9K (o más probablemente de 8K, sin embargo, parece ser un valor por defecto bastante pequeño). Creo que en Windows el buffer de recepción predeterminado es 16K.
Incluso suponiendo que aumentar el buffer de recepción ayuda, usted todavía tiene que abordar los problemas que otros han mencionado. Un par de otras cosas a considerar es tal vez tratar de determinar dinámicamente el tamaño máximo del paquete para evitar la fragmentación. Además, puede tener sentido hacer que el tamaño del paquete y la cantidad de paquetes enviados entre acks se puedan configurar manualmente.
TCP existe para resolver exactamente este tipo de problema. ¿Por qué TCP no es una opción? Tendrás que resolver todos los mismos problemas y finalmente terminar con la misma solución, solo sin el beneficio de décadas de investigación, desarrollo y depuración de la pila TCP.
Si realmente debe usar UDP, la primera pregunta es, ¿qué está dispuesto a renunciar con respecto a las garantías del TCP? ¿Estás contento de recibir paquetes fuera de servicio? ¿Está bien perder algún porcentaje de paquetes? ¿Puedes manejar la llegada de paquetes duplicados? Las respuestas a estas preguntas con suerte conducirán a un diseño.
Sin conocer sus detalles, es imposible responder a su pregunta con un simple "Haz esto y estarás bien", excepto, por supuesto, "Haz TCP y estarás bien".
UDP transmite datagramas y no es confiable.
TCP transmite flujos de datos y es confiable.
Lo que desea parece estar basado en datagramas, pero confiable. Entonces, necesitas construir algo en UDP o TCP para darte eso. Estoy seguro de que hay especificaciones de protocolo completas que se basan en UDP y que proporcionan precisamente eso. Solo tienes que encontrarlos e implementarlos.
Llamar UDP no confiable es una simplificación que intenta poner TCP como una panacea de todos los males de red. En la misma línea, definir TCP como confiable es nuevamente erróneo. Si bien es cierto que TCP tiene mecanismos para intentar asegurar que se transfieran datos, muchas de las fallas que causan la falla de un paquete UDP llegarán a causar que TCP falle.
Por ejemplo, un error de red de hardware tendrá el mismo efecto en los paquetes UDP y TCP. Si la falla persiste, el TCP no se procesará tan seguro como UDP. De hecho, en este caso TCP tiene la desventaja de que intentará completar una causa perdida durante más tiempo. Ahora, si está enviando datos a través de Internet, el TCP tiene algunas ventajas porque la ruta a la que se envía el paquete no se puede predefinir. Sin embargo, para enviar datos a través de una LAN, UDP es perfectamente adecuado. Si sus paquetes no llegan al destino, entonces indica un error de hardware que debe corregirse. TCP no ayudará aquí.
Además, al elegir su protocolo, también debe comprender sus datos. Si sus datos son transitorios, por ejemplo, una lectura de un sensor, tiene mucho más sentido usar UDP sobre TCP. Si se pierde un paquete en esta situación, entonces tiene poca importancia, ya que pronto habrá otro paquete. TCP, por otro lado, retrocederá y volverá a intentarlo. Para cuando los datos lleguen, ya estarán desactualizados.
La verdad es que TCP fue diseñado para transmitir datos. En esta situación, es importante que todos los paquetes de datos lleguen confiables y en orden. UDP es para paquetes de datos y es para este tipo de datos. UDP es perfectamente aceptable, como confiable, tiene menos sobrecarga y es más rápida de detectar y recuperar de fallas de red.
De todos modos, sendto () siempre indica éxito. Esto siempre sucede cuando pruebo mi software a través de una interfaz loopback (127.0.0.1) pero nunca a través de mi red LAN.
Si agrego algo como std :: cout << "test" << std :: endl; entre el sendto () entonces se recibe cada fotograma.
Eso suena como que el buffer de tu receptor es muy pequeño.
algún consejo:
- Aumenta el buffer del receptor. setsockopt SO_RCVBUF
- Deje que la aplicación decida si retransmite el paquete de pérdida.
- Asegúrese de que la carga útil se ajuste a la MTU, lo que significa carga útil + HEADER <= 1500, para evitar la fragmentación de la ip.