servidor - socket udp java
¿Qué haría que los paquetes UDP se descartaran al enviarlos a localhost? (5)
Estoy enviando datagramas muy grandes (64000 bytes). Me doy cuenta de que el MTU es mucho más pequeño que 64000 bytes (un valor típico es de alrededor de 1500 bytes, según mis lecturas), pero sospecho que sucedería una de dos cosas: o ningún datagrama pasaría (todo con más de 1500 bytes) se eliminarán silenciosamente o provocarán un error / excepción) o los datagramas de 64000 bytes se fragmentarán en aproximadamente 43 mensajes de 1500 bytes y se transmitirán de forma transparente.
Durante un largo período de tiempo (más de 2000,000 datagramas de 64000 bytes), aproximadamente el 1% (que parece anormalmente alto incluso para una LAN) de los datagramas se descarta. Podría esperar esto a través de una red, donde los datagramas pueden llegar desordenados, descartarse, filtrarse, etc. Sin embargo, no esperaba esto cuando se ejecuta en localhost.
¿Qué está causando la incapacidad para enviar / recibir datos localmente? Me doy cuenta de que UDP no es confiable, pero no esperaba que fuera tan poco confiable en localhost. Me pregunto si solo se trata de un problema de tiempo, ya que tanto los componentes de envío como de recepción están en la misma máquina.
Para completar, he incluido el código para enviar / recibir datagramas.
Enviando:
DatagramSocket socket = new DatagramSocket(senderPort);
int valueToSend = 0;
while (valueToSend < valuesToSend || valuesToSend == -1) {
byte[] intBytes = intToBytes(valueToSend);
byte[] buffer = new byte[bufferSize - 4];
//this makes sure that the data is put into an array of the size we want to send
byte[] bytesToSend = concatAll(intBytes, buffer);
System.out.println("Sending " + valueToSend + " as " + bytesToSend.length + " bytes");
DatagramPacket packet = new DatagramPacket(bytesToSend,
bufferSize, receiverAddress, receiverPort);
socket.send(packet);
Thread.sleep(delay);
valueToSend++;
}
Recepción:
DatagramSocket socket = new DatagramSocket(receiverPort);
while (true) {
DatagramPacket packet = new DatagramPacket(
new byte[bufferSize], bufferSize);
System.out.println("Waiting for datagram...");
socket.receive(packet);
int receivedValue = bytesToInt(packet.getData(), 0);
System.out.println("Received: " + receivedValue
+ ". Expected: " + expectedValue);
if (receivedValue == expectedValue) {
receivedDatagrams++;
totalDatagrams++;
}
else {
droppedDatagrams++;
totalDatagrams++;
}
expectedValue = receivedValue + 1;
System.out.println("Expected Datagrams: " + totalDatagrams);
System.out.println("Received Datagrams: " + receivedDatagrams);
System.out.println("Dropped Datagrams: " + droppedDatagrams);
System.out.println("Received: "
+ ((double) receivedDatagrams / totalDatagrams));
System.out.println("Dropped: "
+ ((double) droppedDatagrams / totalDatagrams));
System.out.println();
}
¿Qué está causando la incapacidad para enviar / recibir datos localmente?
Mayormente espacio de buffer. Digamos que está enviando una constante de 10MB / segundo, y solo puede consumir 5MB / segundo, el sistema operativo y la pila de red no pueden mantener el ritmo, por lo que soltará los paquetes, esto debería ser bastante obvio. (Que, naturalmente, es diferente de TCP, que proporciona control de flujo y retransmisión para manejar dicha situación).
Incluso si normalmente se mantiene al día con el consumo de datos, es posible que haya pequeños segmentos de tiempo en los que no está. por ejemplo, un recolector de basura entra en funcionamiento, el sistema operativo decidió programar otro proceso en lugar de su consumidor durante 0,5 segundos, etc., y el sistema lanzará paquetes.
Esto se puede extender a cualquier dispositivo de red en el medio. Si está ejecutando en una red en lugar de solo localmente, un conmutador ethernet, un enrutador, etc. también lanzará paquetes si sus colas están llenas (por ejemplo, está enviando una transmisión de 10MB / s a través de un conmutador de Ethernet de 100MB / s, y unos segundos en la mitad de la noche, alguien más intenta meter 100MB / seg por el mismo camino, algunos paquetes perderán).
Intente aumentar el tamaño del búfer de socket , a menudo también debe aumentarlo en el nivel del sistema operativo.
(Por ejemplo, en Linux, el tamaño predeterminado del búfer de sockets es a menudo 128k o menos, lo que deja muy poco espacio para detener el procesamiento de datos, puede intentar aumentarlos estableciendo sysctl net.core.wmem_max, net.core.wmem_default, net.core.rmem_max, net.core.rmem_default)
No sé qué te hace esperar un porcentaje inferior al 1% de los paquetes descartados para UDP.
Dicho esto, según RFC 1122 (ver sección 3.3.2 ), el tamaño máximo de búfer garantizado para no dividirse en múltiples datagramas IP es de 576 bytes. Se pueden transmitir datagramas UDP más grandes, pero es probable que se dividan en múltiples datagramas IP para ser reensamblados en el punto final receptor.
Me imagino que una razón que contribuye a la alta tasa de paquetes descartados que está viendo es que si se pierde un paquete IP que formaba parte de un datagrama UDP grande, se perderá todo el datagrama UDP. Y está contando datagramas UDP, no paquetes IP.
No se garantiza que los paquetes UDP lleguen a su destino mientras que TCP lo está!
Sus expectativas, tal como se expresan en su pregunta y en numerosos comentarios a otras respuestas, son incorrectas. Todo lo siguiente puede suceder incluso en ausencia de enrutadores y cables.
Si envía un paquete a un receptor y no hay espacio en el búfer de recepción de su socket, se eliminará.
Si envía un datagrama UDP más grande que la ruta MTU, se fragmentará en paquetes más pequeños, que están sujetos a (1).
Si no llegan todos los paquetes de un datagrama, el datagrama nunca será entregado.
La pila TCP / IP no tiene obligación de entregar paquetes o datagramas UDP en orden.
La programación de paquetes UDP puede ser manejada por múltiples hilos en el nivel del sistema operativo. Eso explicaría por qué los recibes fuera de servicio incluso en 127.0.0.1.