0
votes

I am programming an Android tablet app. It communicates via UDP messages (13 bytes data each). Sending these packets works correctly. But when I try to receive unicast UDP packets on port 15731 (and on other ports as well), it always returns IOException. That's what my code looks like (receiveUDP runs cyclic).

public void receiveUDP() {
    byte[] buffer = new byte[13];
    try {
        DatagramPacket dataIn = new DatagramPacket(buffer, buffer.length);
        DatagramSocket recSocket = new DatagramSocket(15731);
        recSocket.setSoTimeout(1000);
        recSocket.receive(dataIn);
        Log.i("receiveUDP", "UDP Message received: " + buffer.toString());
        recSocket.close();
    } catch (IOException e) {
        Log.i("receiveUDP", "IOException");
    }
    ;
}

In the Android Manifest I made the following permissions:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

The e.printfStackTrace() command turns out the following:

11-17 14:34:05.130: WARN/System.err(25961): java.net.BindException: Address already in use
11-17 14:34:05.140: WARN/System.err(25961):     at org.apache.harmony.luni.platform.OSNetworkSystem.bind(Native Method)
11-17 14:34:05.140: WARN/System.err(25961):     at dalvik.system.BlockGuard$WrappedNetworkSystem.bind(BlockGuard.java:275)
11-17 14:34:05.140: WARN/System.err(25961):     at org.apache.harmony.luni.net.PlainDatagramSocketImpl.bind(PlainDatagramSocketImpl.java:77)
11-17 14:34:05.140: WARN/System.err(25961):     at java.net.DatagramSocket.createSocket(DatagramSocket.java:190)
11-17 14:34:05.140: WARN/System.err(25961):     at java.net.DatagramSocket.<init>(DatagramSocket.java:74)
11-17 14:34:05.140: WARN/System.err(25961):     at com.example.MyService.onCreate(MyService.java:78)
11-17 14:34:05.140: WARN/System.err(25961):     at android.app.ActivityThread.handleCreateService(ActivityThread.java:2103)
11-17 14:34:05.140: WARN/System.err(25961):     at android.app.ActivityThread.access$1500(ActivityThread.java:122)
11-17 14:34:05.140: WARN/System.err(25961):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1078)
11-17 14:34:05.140: WARN/System.err(25961):     at android.os.Handler.dispatchMessage(Handler.java:99)
11-17 14:34:05.140: WARN/System.err(25961):     at android.os.Looper.loop(Looper.java:132)
11-17 14:34:05.140: WARN/System.err(25961):     at android.app.ActivityThread.main(ActivityThread.java:4123)
11-17 14:34:05.140: WARN/System.err(25961):     at java.lang.reflect.Method.invokeNative(Native Method)
11-17 14:34:05.140: WARN/System.err(25961):     at java.lang.reflect.Method.invoke(Method.java:491)
11-17 14:34:05.140: WARN/System.err(25961):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
11-17 14:34:05.140: WARN/System.err(25961):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
11-17 14:34:05.140: WARN/System.err(25961):     at dalvik.system.NativeStart.main(Native Method)

What does this mean?

Now, if I don't create DatagramSocket and DatagramPacket cyclic any more, I get a different stack trace. It is:

11-17 15:06:42.590: WARN/System.err(26812): android.os.NetworkOnMainThreadException
11-17 15:06:42.590: WARN/System.err(26812):     at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1077)
11-17 15:06:42.590: WARN/System.err(26812):     at dalvik.system.BlockGuard$WrappedNetworkSystem.recv(BlockGuard.java:332)
11-17 15:06:42.590: WARN/System.err(26812):     at org.apache.harmony.luni.net.PlainDatagramSocketImpl.doRecv(PlainDatagramSocketImpl.java:165)
11-17 15:06:42.590: WARN/System.err(26812):     at org.apache.harmony.luni.net.PlainDatagramSocketImpl.receive(PlainDatagramSocketImpl.java:174)
11-17 15:06:42.590: WARN/System.err(26812):     at java.net.DatagramSocket.receive(DatagramSocket.java:391)
11-17 15:06:42.590: WARN/System.err(26812):     at com.example.MyService.onCreate(MyService.java:114)
11-17 15:06:42.610: WARN/System.err(26812):     at android.app.ActivityThread.handleCreateService(ActivityThread.java:2103)
11-17 15:06:42.610: WARN/System.err(26812):     at android.app.ActivityThread.access$1500(ActivityThread.java:122)
11-17 15:06:42.610: WARN/System.err(26812):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1078)
11-17 15:06:42.610: WARN/System.err(26812):     at android.os.Handler.dispatchMessage(Handler.java:99)
11-17 15:06:42.610: WARN/System.err(26812):     at android.os.Looper.loop(Looper.java:132)
11-17 15:06:42.610: WARN/System.err(26812):     at android.app.ActivityThread.main(ActivityThread.java:4123)
11-17 15:06:42.610: WARN/System.err(26812):     at java.lang.reflect.Method.invokeNative(Native Method)

Has anyone an idea why I can't receive UDP packets?

3
What's the message and stack trace of the IOException?millimoose
Does e.getMessage() give any insights in the catch?FunkTheMonk
I have copied the content of e.printStackTrace in the question. Can you say what it means? I'm pretty new to Java and Android and I have not worked with stack trace til now...user1051742

3 Answers

4
votes

A couple of things:

Since you reuse the same port, you might need to create a socket, call setReuseAddress(true), and then bind the socket to the port.

InterruptedIOException is a subclass of IOException, setSOTimeout(1000); will only wait (block) for 1 second before throwing this exception

UPDATED: The exceptions show the problems:

java.net.BindException: Address already in use

Which I believe will be fixed by using the setReuseAddress (above)?

and

android.os.NetworkOnMainThreadException

Which means you're running this code on a the main UI thread, which will block the responiveness of the UI and possibly cause an ANR (probably not if you keep setSOTimeout(1000), but anyway...). 3.0 and later doesn't allow network requests on the UI thread so you need to put it into an AsyncTask (or Thread).

0
votes

You may have networking issues if you are trying this on emulator. Emulator is a virtual machine which is connected directly to your router device. Your emulator cannot reach your local device, or any other devices on the local network.

So that, if you wait answer from your local machine, or another machine on the lan, you may need portforwarding.

First try your application on a real device to decide if it is an emulator problem or not, than try other solutions.

0
votes

I used UDP Broadcast on 3.2 once and it worked

Simplified Code of mine:

DatagramSocket socket;
socket = new DatagramSocket(aport);
socket.setBroadcast(true);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);

This worked for me. If you use broadcasts try setBroadcast(true).