Lance
Lance

Reputation: 260

Android: java.net.DatagramSocket.bind: Invalid Argument Exception

Background: I'm writing a simple UDP application to ping a beta server I manage every minute or so to tell me it is still up and running (I can't enable ping on the server for those that are wondering). I plan to run this on my phone to warn me when the server is no longer responding.

I'm trying to use the seemingly simple java.net.DatagramSocket as such:

    try
    {
        socket = new DatagramSocket();
        socket.bind(null);
    } 
    catch (SocketException e)
    {
        System.out.println(e.toString());
        throw e;
    }

Let me also say that I have enabled the Internet permissions through the android manifest and if I remove the uses clause to do so, I get a permissions error so I'm sure that is working OK. When I download this code to an Android Virtual Device (AVD) and execute it, on the call to bind() I am presented with this exception:

03-17 19:07:39.401: INFO/System.out(338): java.net.BindException: Invalid argument

According to this documentation, the null argument is correct:

public void bind (SocketAddress localAddr)

Since: API Level 1

Binds this socket to the local address and port specified by localAddr. If this value is null any free port on a valid local address is used.

But not trusting documentation, I decided to enumerate the IP addresses on my device like this:

    ArrayList<NetworkInterface>  allInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
    
    NetworkInterface eth = allInterfaces.get(0);
                
    InetSocketAddress addr = new InetSocketAddress(eth.getInetAddresses().nextElement(), port);
    
    try
    {
        socket = new DatagramSocket();
        socket.bind(addr);
    } 
    catch (SocketException e)
    {
        System.out.println(e.toString());
        throw e;
    }

When I step through the code, it works great and I can see the two IP address on the AVD but I get the exact same exception on the bind() call. Does anybody out there see what i might be missing? I will continue to research and hopefully post a solution to my own problem, but I am hoping somebody out there will be able to shortcut this for me.

Upvotes: 8

Views: 8800

Answers (2)

Newtron
Newtron

Reputation: 426

I've stumbled across this problem either and have found the cause: if you call the parameterless constructor new DatagramSocket(), this creates "a UDP datagram socket which is bound to any available port on the local host using a wildcard address" (as per the API docs). So this actually means, the Socket is already bound. My "fix" for this is as follows:

        SocketAddress socketAddress = new SocketAddress(yourInetAddress, yourPort);
        DatagramSocket serverSocket = new DatagramSocket(null);
        serverSocket.bind(socketAddress);

This explicitly creates an unbound Socket (through the DatagramSocket (SocketAddress localAddr) constructor), making it possible to bind the Socket in turn.

This is probably the more elegant solution than creating an unnecessary channel.

P.S.: Strangely enough, this is where DatagramSocket differs from a TCP ServerSocket: the parameterless constructor of the latter will create an unbound ServerSocket, not triggering this problem.

Upvotes: 3

Lance
Lance

Reputation: 260

[Edited: if you saw my previous response I made the classic debugging mistake of changing two variable in one test and it was the other one that solved my problem.]

I found the problem. It is the way I'm declaring the DatagramSocket that appears to cause problems. If I use a DatagramChannel to open the DatagramSocket in the following way then the bind() call is successful.

      DatagramChannel channel = DatagramChannel.open();
      DatagramSocket socket = channel.socket();

Upvotes: 9

Related Questions