Pérdida de paquetes mientras recibe la transmisión UDP en el dispositivo android

Para recibir paquetes de difusión UDP desde el servidor a un dispositivo android, utilicé una clase de servicio y escuché paquetes en un subproceso. Recibe el paquete correctamente. El problema es que si se envían varios paquetes desde el servidor al mismo tiempo, la pérdida de paquetes será el resultado.

Incluso intenté con una cola y el procesamiento de los paquetes recibidos en el hilo separado, entonces también no estoy recibiendo el paquete. Soy completamente nuevo en la programación de la red cualquier ayuda sería ampliamente apreciada

void startListenForUdpBroadcast() { UDPBroadcastThread = new Thread(new Runnable() { public void run() { try { InetAddress broadcastIP = InetAddress.getByName(UdpConstants.IP_ADDRESS); Integer port = UdpConstants.RECEIVER_PORT; while (shouldRestartSocketListen) { listenAndWaitAndThrowIntent(broadcastIP, port); } } catch (Exception e) { Log.i("UDP", "no longer listening for UDP broadcasts cause of error " + e.getMessage()); } } }); UDPBroadcastThread.setPriority(Thread.MAX_PRIORITY); //Setting The Listener thread to MAX PRIORITY to minimize packet loss. UDPBroadcastThread.start(); } 

Este código escucha paquetes nuevos y empuja a la cola

 private void listenAndWaitAndThrowIntent(InetAddress broadcastIP, Integer port) throws Exception { byte[] recvBuf = new byte[64000]; if (socket == null || socket.isClosed()) { socket = new DatagramSocket(port, broadcastIP); socket.setBroadcast(true); } //socket.setSoTimeout(1000); DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length); socket.receive(packet); messQueue.add(packet); } 

Esto verifica la cola de mensajes nuevos y procesa

  /** * @purpose Checking queue and If anything is added to the queue then broadcast it to UI */ private void checkQueue() { queueThread = new Thread(new Runnable() { public void run() { try { while (shouldRestartSocketListen) { if (!messQueue.isEmpty()) { broadcastIntent(messQueue.poll()); } } } catch (Exception e) { } } }); queueThread.start(); } 

El problema con UDP es que su remitente (su servidor) no sabe que (su dispositivo Android) se perdió algunos. No se pierde porque no se puede leer lo suficientemente rápido, a veces sólo sobre la interferencia de aire / congestión o un zócalo ocupado.

El receptor sólo sabría si:

  1. Obtiene un error al procesar los datos, ya que faltan datos
  2. O sus paquetes UDP se numeran secuencialmente en su encabezado y se detecta un número que falta (por ejemplo, 1,2,4 – falta 3)

Una vez que el paquete se pierde, se pierde. Tienes dos opciones:

  1. Implementar una solicitud de reenvío: al detectar un paquete faltante, el receptor necesitaría notificar al remitente para reenviar ese paquete faltante hasta que lo obtenga, y su procesamiento de paquetes podría ser detenido hasta que no
  2. O ser capaz de ignorarlo, "hey, podemos hacerlo sin él", y rellenar con datos en blanco (por ejemplo, un mapa de bits tendría algunos píxeles en blanco, como una imagen rota)
  3. Acelerar su velocidad de envío por lo que los paquetes no se atascan y se pierden
  4. Cuanto más pequeños sean tus paquetes, más probable es que vivan

(Opción 1: todo esto volver a solicitar es simplemente pseudo-TCP, por lo que sólo podría considerar abandonar UDP y ir TCP)

Si recibe varios datagramas en una ráfaga corta, su bucle receptor puede tener problemas para mantenerse al día, y el nivel OS-RCVBUF en el zócalo puede desbordar (haciendo que el sistema operativo deje caer un paquete que efectivamente recibió).

Es posible que obtenga un mejor manejo de ráfagas cortas si aumenta el tamaño de RCVBUF. Antes de hacer esto, tener una idea de lo grande que ya es a través de socket.getReceiveBufferSize. También tenga en cuenta que el número de bytes en el búfer de recepción debe acomodar no sólo la carga útil, sino también los encabezados y la estructura sk_buff que almacena los paquetes en el kernel (ver, por ejemplo, lxr.free-electrons.com/source/include/linux / …).

Puede ajustar el tamaño del búfer receptor a través de socket.setReceiveBufferSize – pero tenga en cuenta que este mensaje es sólo una pista y puede ser anulado por los ajustes en el kernel (si solicita un tamaño mayor que el tamaño máximo permitido por la red actual del kernel Configuración, entonces sólo obtendrá el tamaño máximo).

Después de solicitar un buffer de recepción más grande, debe comprobar lo que el kernel ha permitido llamando a socket.getReceiveBufferSize.

Si tiene los permisos adecuados, debería poder ajustar el tamaño máximo del búfer que el núcleo le permitirá – ver, por ejemplo, https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Administration_And_Configuration_Guide/jgroups- Perf-udpbuffer.html

[Tenga en cuenta que, en general, esto se adaptará a ráfagas cortas donde los datagramas llegan más rápido de lo que su bucle cliente puede leer, pero si el bucle cliente es crónicamente más lento que la entrega del datagrama, todavía obtendrá gotas ocasionales debido al desbordamiento. En este caso, debe acelerar el bucle del cliente o ralentizar el remitente.

Además, como se indica en otras respuestas, los paquetes pueden ser eliminados por su red, y las redes móviles pueden ser propensas a esto, por lo que si necesita una entrega garantizada debe utilizar TCP. Sin embargo, si este fuera su problema principal, esperaría ver paquetes perdidos incluso cuando su servidor los envíe lentamente, en lugar de hacerlo en una ráfaga.]

Creo que tu problema es que usas Udp Broadcast sobre wifi.

Son dos respuestas muy bien documentadas por qué es una forma muy lenta de operar y por qué hay mucho más paquetes perdidos:

  • Respuesta número uno .

  • Respuesta número dos.

Lo que hice para solucionar el ancho de banda extremadamente lento fue algún tipo de protocolo multi-unicast:

  1. Administre la lista de clientes que ha conectado.
  2. Envíe cada paquete que tenga en su servidor a todos sus clientes por separado con enviar llamada.

Este es el código en java:

  DatagramPacket packet = new DatagramPacket(buffer, size); packet.setPort(PORT); for (byte[] clientAddress : ClientsAddressList) { packet.setAddress(InetAddress.getByAddress(clientAddress)); transceiverSocket.send(packet); } 

Supongo que usted está captando sólo un solo paquete diciendo

 socket.receive(packet); 

Esto es una llamada de E / S de bloqueo que esperará infinitamente hasta que reciba un paquete así que una vez que el primer paquete llega es hecho esperando y el siguiente comando ejecuta ie

 messQueue.add(packet); 

Sin embargo, cuando se reciben varios paquetes, debe seguir recibiendo paquetes. En su caso usted acaba de dejar de recibir paquetes después de la llegada del primer paquete

Nota: UDP que es un protocolo un-reliable no garantiza la entrega del paquete así que puede haber un caso que un paquete se pierde, sin embargo esto no puede ser un problema en cada funcionamiento de su programa, sin embargo una manera agradable de comprobar si el paquete Está golpeando su máquina y el problema está dentro de su aplicación (la aplicación no es capaz de manejar los paquetes recibidos) use tcpdump (es una utilidad de línea de comandos para Linux basado en SO o MAC) use el siguiente comando

  sudo tcpdump -i <interface name(one that handles traffic) eth0, eth1 .. en0, en1 (for MAC)> host <ipaddress or hostname of UDP Broadcast server> 

Ejemplo:

 sudo tcpdump -i en1 host 187.156.13.5 

(Si el comando tcpdump no se encuentra, vaya adelante e instálelo)

Usando este comando usted verá los paquetes que bombean adentro del servidor del ump del destino en terminal si usted ve más entonces que un paquete que llega entonces usted estaría seguro que los paquetes están llegando en la máquina. Sin embargo la aplicación cae brevemente para dirigir el paquete

podría ayudar

Con referencia a la explicación anterior por mí los cambios siguientes que usted puede hacer para hacer que el código se comporte según el requisito

Supongo que puede hacer los siguientes cambios para hacer que su trabajo de código de problema en lugar de crear socket en listenAndWaitAndThrowIntent (InetAddress broadcastIP, Integer puerto) método de crearlo en startListenForUdpBroadcast () como sigue

 socket = new DatagramSocket(port, broadcastIP); socket.setBroadcast(true); while (shouldRestartSocketListen) { listenAndWaitAndThrowIntent(broadcastIP, port, socket); } 

Ahora también necesita cambiar la implementación del método listenAndWaitAndThrowIntent de la siguiente manera

 private void listenAndWaitAndThrowIntent(InetAddress broadcastIP, Integer port, DatagramSocket socket) throws Exception { byte[] recvBuf = new byte[64000]; //socket.setSoTimeout(1000); //change value of condition in for loop to desired number of packets you would like to receive in below example it is 2 so it captures two packets for (int i=0 ; i <= 2 ; i++ ){ DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length); socket.receive(packet); messQueue.add(packet); } } 

¡Pruebe esto debería funcionar! podría ayudar

  • Encontrar máquinas en la red local basada en el puerto (descubrimiento de red) en android
  • Android (Java) los recursos de programación de red
  • Cómo reanudar el proceso de carga de archivos en Android?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.