0

I'm writing a Peer-to-Peer Application. I have a default port the application to bind to. But if this fails, I want my application to bind to another open port.

I have a solution for this but I think it's not a very brilliant one.

I'm thinking of something like this:

    package de.oompf.netwrk;

    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetSocketAddress;
    import java.net.SocketException;

    class Server implements Runnable {
        private final Thread serverThread;
        private final DatagramSocket socket;

        Server() throws SocketException {
            serverThread = new Thread(this, "Server Thread");
            socket = new DatagramSocket(null);
            socket.setSoTimeout(2400);

            for(int port : Configuration.getPortList()) {
                if(!socket.isBound()) {
                    try {
                        socket.bind(new InetSocketAddress(port));
                        break;
                    } catch(SocketException e) {
                    }
                } else {
                    break;
                }
            }

            if(!socket.isBound()) {
                socket.bind(new InetSocketAddress(0));
            }
        }

        void start() {
            serverThread.start();
        }

        void stop() {
            serverThread.interrupt();
            socket.close();
        }

        @Override
        public void run() {
            DatagramPacket p = new DatagramPacket(new byte[4096], 4096);
            while(!serverThread.isInterrupted()) {
                try {
                    socket.receive(p);
                } catch (IOException e) {
                    if(socket.isClosed()) {
                        break;
                    }
                }
            }
        }

    }

But the socket gets closed after the first unsuccessful try to bind it to a port.

So what's the most elegant way to do this in Java?

Marcel
  • 245
  • 4
  • 9
  • I worked on the same thing some time ago, and I solved it by creating a PortScanning method, that returns the value of next available port. Then I pass that port to my Connection thread – Ubica Dec 28 '14 at 22:55
  • Your `for` loop is always interrupted (`break;`) regardless of the success of binding. – PM 77-1 Dec 28 '14 at 22:57
  • No, it isn't. There are two 'break' statements. The first only gets executed on success of the bind(). – Marcel Dec 28 '14 at 23:02
  • 1
    A similar question with numerous useful answers is here: http://stackoverflow.com/questions/2675362/how-to-find-an-available-port – Donald_W Dec 28 '14 at 23:50
  • Why not bind to port `0` and let the operating system pick the right port for you – Jakob Bowyer Dec 29 '14 at 00:14
  • I need this for bootstrapping purposes. – Marcel Dec 29 '14 at 00:18

2 Answers2

0

try this

       for(int port : Configuration.getPortList()) {
            if(!socket.isBound()) {
                try {
                    socket.bind(new InetSocketAddress(port));
                    break;
                } catch(Exception e) {
                }
            } 
        }


    }
0

The solution is to create a new socket for each port you need to test. Your problem with this is that you have declared your socket field final. So the solution to that is to create a local variable to store the socket until you are sure you have a successfully bound socket or delegate the creation of the socket to another method.

DatagramSocket socket = null;
for (int port : Configuration.getPortList()) {
    try {
        socket = new DatagramSocket(port);
        break;
    } catch (SocketException ignored) {
        continue;
    }
}
if (socket == null) {
    socket = new DatagramSocket(0); 
}
this.socket = socket;

OR

Server() throws SocketException {
    serverThread = new Thread(this, "Server Thread");
    socket = getBoundSocket();
    socket.setSoTimeout(2400);
}

private static DatagramSocket getBoundSocket() throws SocketException {
    for (int port : Configuration.getPortList()) {
        try {
            return new DatagramSocket(port);
        } catch (SocketException ignored) {
            continue;
        }
    }
    return new DatagramSocket(0); 
}
Marcel
  • 245
  • 4
  • 9
Dunes
  • 37,291
  • 7
  • 81
  • 97
  • Thanks! The first solution was what I meant with 'I have a solution for this'. But the second method is the best way to do it, I have seen so far. – Marcel Dec 29 '14 at 00:05