Bevor
Bevor

Reputation: 8605

How to reuse DatagramSocket?

I have a problem using DatagramSocket. The problem is that I can't run two Android JUnit tests one after another using DatagramSockets because the second tests throws the following exception:

java.net.BindException: Address already in use

I guess this will be a problem in Activities too, because when the Activity moves from background to foreground, I would probably get the same exceptions.

I'm satisfied if I could either disconnect and reconnect the socket or if I'm able to reuse the old socket but I can't get one of them working. My reusing concept looked like this:

    if (serverSocket == null || !serverSocket.isBound())  {
        serverSocket = new DatagramSocket(9800);
    }

But this doesn't work, same exception. It doesn't even work when I try to reinstantiate it (when I don't negate the 2nd term).

I tried to dis- and reconnect it...

        serverSocket.disconnect();
        serverSocket = new DatagramSocket(null); 
        serverSocket.setReuseAddress(true);
        serverSocket.bind(new InetSocketAddress("localhost", 9800));

Doesn't work either. Same exception when executing the second test. What can I do to solve this? Here is the whole class:

public class UdpListener extends Thread implements Subject {
    private DatagramSocket serverSocket;
    private DatagramPacket receivedPacket;
    private volatile boolean running = false;
    private String sentence = "";

    private Observer observer;

    private static final String TAG = "UdpListener";

    public UdpListener(Observer o) throws SocketException  {
        observer = o;

        if (serverSocket == null || !serverSocket.isBound())  {
            serverSocket = new DatagramSocket(9800);
        }
    }

    @Override
    public void run() {
        setName(TAG);
        while (isRunning())  {
            byte[] receivedData = new byte[1024];
            receivedPacket = new DatagramPacket(receivedData, receivedData.length);
            try {
                serverSocket.receive(receivedPacket);
            } 
            catch (IOException e) {
                Log.w(TAG, e.getMessage());
            }

            try {
                sentence = new String(receivedPacket.getData(), 0, receivedPacket.getLength(), "UTF-8");
                if (UdpState.UPDATE.toString().equals(sentence))  {
                    notifyObserver();
                }
            } 
            catch (UnsupportedEncodingException e) {
                Log.w(TAG, e.getMessage());
            }
        }
    }

    private boolean isRunning() {
        return running;
    }

    public void setThreadRunning(boolean running) throws SocketException {
        this.running = running;
        if (running)  {
//          serverSocket = new DatagramSocket(9800);
            this.start();
        }
        else  {
//          serverSocket.disconnect();
//          serverSocket = new DatagramSocket(null); 
//          serverSocket.setReuseAddress(true);
//          serverSocket.bind(new InetSocketAddress("localhost", 9800));
        }
    }

    @Override
    public void notifyObserver() {
        observer.update();
    }
}

Upvotes: 1

Views: 6495

Answers (2)

Green Day
Green Day

Reputation: 664

ok I was just looking at your code for a while and I just realized you never call:

serverSocket.close();

call it after you call:

serverSocket.disconnect();

and your problem should be solved.

Upvotes: 3

Perception
Perception

Reputation: 80633

Your code:

if (serverSocket == null || !serverSocket.isBound())  {
    serverSocket = new DatagramSocket(9800);
}

Will be short-circuited if the serverSocket instance is null, aka the second check to ensure it is not bound may not get called.

Keep in mind also that there may be a lag period between calling disconnect on your Datagram socket and when the OS actually releases said socket for reuse.

Upvotes: 0

Related Questions