java - android UDP unreliability

502 views Asked by At

I am having extreme UDP packet losses with Android and it does not make sense. The situation is as follows:

  1. PC running java client connected to home network
  2. Phone running java server (android) connected to home network
  3. Home router is a brand new WRT1900ac. Network has internet connectivity.
  4. UDP packets are small (< 15 bytes)

Symptoms:

  1. If PC sends UDP packet to another PC (both on same network) it works very well (almost no packets lost).

  2. If Android sends UDP packet to PC on the same network it also works very well (almost no packets lost).

  3. If PC sends UDP to Android on the same network I get extreme packet losses (50% of the time or more - but it varies).

Most times I am forced to send the packet like 10 times to get one through. Other times all get through with quite some delay. Very strange behavior that only happens on the receiving end of android. If I replace android with pc running the same code on java or simply receiving the packet through Packet Sender's UDP server I have no loss issues. Another thing I noticed is that if instead of going through the router I go through another access point that has no internet connectivity or no other clients performance seems to dramatically improve. This is expected, but my question is why Android's receiving end is seeing such poor performance and losing so many packets. When Android is replaced with another PC running the same code and on the same network there are no issues. Android also has no issues sending out the packets (no packets are lost). Therefore it has to be something else android related on the receiving end...

I have also tried replacing the PC code with Packet Sender and I get the same results. The problem seems to be Android's receiving end. I run the same UDP code on the PC side and on android.

The UDP sending code is simple:

public void sendMessage(String message)
{
    try {
        DatagramSocket ds = new DatagramSocket();
        DatagramPacket dp;
        InetAddress local = InetAddress.getByName(ipPool);
        dp = new DatagramPacket(message.getBytes(), message.length(), local, port);
        ds.setBroadcast(true);
        ds.send(dp);
        ds.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

The UDP receiving code on android lives in a UDP server class:

public class UDP_Server
{
    CommandParser commandParser;

    public UDP_Server(MainActivity mainActivity)
    {
        Log.i("Udp tutorial", "---------------------------Starting UDP SERVER");

        commandParser = new CommandParser(mainActivity);
        String text;
        int server_port = 9876;
        try
        {
            DatagramSocket s = new DatagramSocket(server_port);
            s.setBroadcast(true);
            //s.setReceiveBufferSize(163840);


            while (true)
            {
                byte[] message = new byte[1024];
                DatagramPacket p = new DatagramPacket(message, message.length);

                s.receive(p);
                text = new String(message, 0, p.getLength());
                Log.d("Udp tutorial","message:" + text);
                //commandParser.parseCommand(text);
                //s.close();
            }
        } catch (SocketException e)
        {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

The UDPServer.java class is instantiated through the main activity "onCreate()" method:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);

        wm = (WifiManager) getSystemService(WIFI_SERVICE);

        Log.i("Udp tutorial", "---------------------------HERE 1");
        Thread thread = new Thread(new Runnable()
        {
            public void run()
            {
                UDP_Server svr = new UDP_Server(MainActivity.this);
            }
        });

        thread.setPriority(Thread.MAX_PRIORITY);
        thread.start();
//        TCPServer server = new TCPServer();
    }
1

There are 1 answers

0
Clément Mangin On

I had catastrophic results with some Android devices sending a file to a TFTP (based on UDP) server over WiFi, but it seemed to work well with other Android devices.

Data blocks (from the device to the server) were properly sent, but ack blocks (from the server to the device) seemed to be lost in limbo.

Turns out I had to acquire a multicast lock for those faulty devices to work properly (credits to https://www.b4x.com/android/forum/threads/enable-multicast.43321/#post-263242)

WifiManager wifi = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock multicastLock = wifi.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();

...

multicastLock.release();

Hope this helps.