4
votes

I recently implemented UDP packet sequencing support in my Android (2.3.3 and 4.0.4 specifically) app that broadcasts UDP packets between devices. The sequencing support basically takes any byte[] and chunks it up into UDP friendly sizes and send them out as UDP packets. There's a header I include that helps with UDP sequence identification. Right now it appears as if broadcasting a large data set via it works. Any peers listening for it can reassemble the sequence fine, then process the data accordingly. (I'm broadcasting an image taken with the camera and voice clips)

What I'm finding though is occasionally (often) a packet in the sequence will be dropped. Before anyone says that UDP is not reliable, don't bother. I'm well aware. What's happening here isn't necessarily unreliability.

First the UDP packet sequencing will send out 1 segmented UDP packet every 2 seconds. e.g. if the data is 128K, there will be 3 packets, sent out over a 6 second period. The 2 second number is to help with testing.

Second, I only have 2 devices in my isolated test environment. They're the only ones on the test wifi network.

Third, these devices are doing nothing but testing sending and receiving these UDP packets.

Fourth, my logging tracks a unique sequence based ID for each packet. It helps with determining which packet the sender sent in a sequence, and which the receiver received.

I can't show you logs, it wouldn't help, but the sender will note that every packet has been broadcast, while the receiver will drop one, potentially at any point. Sometimes the receiver gets everything, sometimes it's missing one.

NOW that I've explained all that, does Android queue received UDP packets for a processing socket?

I don't think the receiver is too busy to accept the UDP packets. (they are sent every 2 seconds)

Currently my service starts a Runnable that basically loops on DatagramSocket.receive(), then processes the received packet accordingly.

public class MulticastListenerRunnable implements Runnable {
    ...
    public void run() {
        try {
            multicastServer = new DatagramSocket(port, null);
            byte[] buffer = new byte[DatagramSession.DATAGRAM_MAX_SIZE];
            DatagramPacket packet = null;
            byte[] data;

            while(run) {
                try {
                    packet = new DatagramPacket(buffer, buffer.length);
                    packet.setLength(buffer.length);
                    multicastServer.receive(packet);
if(packet.getAddress().getHostAddress().equals("127.0.0.1") || packet.getAddress().getHostAddress().equals(ipAddress)) {
                        continue;
                    }
                    Log.d(TAG, "START PACKET RECEIVE!");
                    processPacket(packet);
            }
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        } catch (Exception e) {             
            Log.e(TAG, e.getMessage());
        }
    }
}

In my logs I'll literally see: (it's a clip from my log, not from directly the output of the above code clip)

03-21 01:26:35.453: D/CommService(6446): START PACKET RECEIVE!
03-21 01:26:35.507: D/CommService(6446): RECEIVED PACKET:  19 of 28 -> 64977(65000 max)
03-21 01:26:35.515: D/CommService(6446): RECEIVED PACKET: This packet isn't alone. More to come!
03-21 01:26:35.515: D/CommService(6446): END PACKET RECEIVE!


03-21 01:26:39.460: D/CommService(6446): START PACKET RECEIVE!
03-21 01:26:39.468: W/DatagramSession(6446): Warning, this packet's sequence isn't in order, last -> 18, new -> 20
03-21 01:26:39.476: D/CommService(6446): RECEIVED PACKET: This packet isn't alone. More to come!
03-21 01:26:39.476: D/CommService(6446): END PACKET RECEIVE!

Note that packet 20 is missing. If I look on my sender device's logs, I'll see him send out all packets every 2 seconds. You can see in the time code that packet 19 is received at 1:26:35, and packet 21 is received 1:26:39. (4 seconds in between)

I'm kind of at a loss. Is there a know issue with Android and UDP packet loss? Does the Android/Java UDP stack queue received packets for a period of time is the service is too busy processing other packets?

Any suggestions other than switching to TCP would be helpful. Thanks in advance!

1
OK, I stuck wireshark on my test wifi and found that Android isn't actually sending out the UDP packet in the cases where they appear "dropped". I literally have debugged and logged the DatagramSocket.send() call, yet no UDP packet appears in Wireshark. Meaning, in my last test, out of 8 packets, only 6 were received. Packets 4 and 6 were not sent, even though DatagramSocket.send() was called?!?!?dubmojo

1 Answers

1
votes

Ok, I fixed my issue.

I switched my straight single ScheduledExecutorService + Runnable thread in my application Service to a Runnable that will spawn new ExecutorService Runnables to process the received DatagramPacket. I guess there was a little I/O delay/blocking in my receiver and splitting it out into a separate thread to process the packet data appears to work. I've transmitted 1.8MB size data tests between devices using the new approach.