6

I understand that the following code can (perhaps not very efficiently) find out a free TCP port in Java:

  public static int findFreePort() {
    int port;
    try {
      ServerSocket socket= new ServerSocket(0);
      port = socket.getLocalPort();
      socket.close(); 
    } catch (Exception e) { port = -1; }
    return port;    
  } 

(There are some related questions here in SO - for example).

What I don't understand is why (or whether) two succesive calls to this method are guaranteed to return two different ports. This is assumed, for example, here (search for the calls to findFreePort method).

Is this correct?

Community
  • 1
  • 1
leonbloy
  • 73,180
  • 20
  • 142
  • 190
  • If there are related questions you should cite them and link to them. – Freiheit Jul 16 '10 at 14:25
  • It's not reallocated because of SO_WAIT, a mechanism designed to circumvent that a packet still in transit would be received by another process. By default, of you close a TCP port, it is not reallocated for the next 2 minutes to allow these lingering packets to flush. – Agoston Horvath Sep 16 '14 at 14:53
  • It seems to me that that behaviour is perhaps common, but just implementation dependent, no? http://www.tcpipguide.com/free/t_TCPIPClientEphemeralPortsandClientServerApplicatio-2.htm http://technet.microsoft.com/en-us/library/cc759700(v=ws.10).aspx – leonbloy Sep 16 '14 at 15:05
  • I don't know if it's a standard, but definitely a good security/privacy measure. – Agoston Horvath Oct 01 '14 at 07:44

5 Answers5

5

In the Javadoc specification, I don't see any line saying that two succesive calls is guaranteed to return two different ports...

Since the ServerSocket is closed, a second call could give the same port. Statistically, it is unprobable but not impossible I think.

If you open your two ServerSocket, get the ports, and then, close your two ServerSocket, you are guarranted to get two different ports (since the first is not free when you create the second ServerSocket).

Example method to get n different free ports :

public int[] getFreePorts(int portNumber) throws IOException {
    int[] result = new int[portNumber];
    List<ServerSocket> servers = new ArrayList<ServerSocket>(portNumber);
    ServerSocket tempServer = null;

    for (int i=0; i<portNumber; i++) {
        try {
            tempServer = new ServerSocket(0);
            servers.add(tempServer);
            result[i] = tempServer.getLocalPort();
        } finally {
            for (ServerSocket server : servers) {
                try {
                    server.close();
                } catch (IOException e) {
                    // Continue closing servers.
                }
            }
        }
    }
    return result;
}
Benoit Courtine
  • 7,014
  • 31
  • 42
  • 1
    It should be noted that even this solution (and Noel M's) is not 100% foolproof, there is a potential race condition. After this method call, the caller will eventually try to use those available ports. But it could happen that in the meantime some other process has opened it. – leonbloy Jul 17 '10 at 14:14
2

One way to get two different port numbers:

  ServerSocket socket1 = new ServerSocket(0);
  port1 = socket1.getLocalPort();
  ServerSocket socket2 = new ServerSocket(0);
  port2 = socket2.getLocalPort();

  socket1.close();
  socket2.close(); 
Noel M
  • 15,812
  • 8
  • 39
  • 47
0

Here's a class that I have used to find multiple free ports. It provides the flexibility to allocate individual ports in the flow of some complex logic (i.e. when maybe the number of ports you'll need is not a simple number but depends on complex logic). It still guarantees that all the ports you ask for free and unique (as long as you are using the same instance of this class to obtain all the ports).

So the way to use this class would be to create an instance. Execute your code to do whatever it is you want to allocate ports for using that instance. Then, once you have bound all the ports you can dispose of this instance and use a new one next time.

public class PortFinder {

/**
 * If you only need the one port you can use this. No need to instantiate the class
 */
public static int findFreePort() throws IOException {
    ServerSocket socket = new ServerSocket(0);
    try {
        return socket.getLocalPort();
    } finally {
        try {
            socket.close();
        } catch (IOException e) {
        }
    }
}

private HashSet<Integer> used = new HashSet<Integer>();

/**
 * Finds a port that is currently free and is guaranteed to be different from any of the
 * port numbers previously returned by this PortFinder instance.
 */
public synchronized int findUniqueFreePort() throws IOException {
    int port;
    do {
        port = findFreePort();
    } while (used.contains(port));
    used.add(port);
    return port;
}

}
Kris
  • 3,898
  • 1
  • 23
  • 32
  • where is the findFreePort(); method. @Kris – Roster Sep 14 '15 at 11:11
  • It's right there, the first member of the PortFinder class. Maybe I confused things by the unusual ordering of putting it before the field declaration. – Kris Sep 15 '15 at 21:07
0

Source code for ServerSocket is here: http://kickjava.com/src/java/net/ServerSocket.java.htm

I'm not quite seeing how it determines if the port is free or not, but:

@param port the port number, or <code>0</code> to use any
free port.

So once the first port is allocated, even to your application, it is no longer free. So successive calls to ServerSocket will not reuse that port thus guaranteeing two different ports.

Freiheit
  • 8,408
  • 6
  • 59
  • 101
  • But `findFreePort` opens the socket and inmediately closes it, so in theory is again available. – leonbloy Jul 16 '10 at 14:52
  • In the code, the port is allocated, but the "close()" method disallocate this port. Then, it can be resused (by another ServerSocket, for example). So, I think another call to that method could give the same port number. – Benoit Courtine Jul 16 '10 at 14:53
0

It's as efficient as the operating system can make it. However closing the ServerSocket immediately afterwards is pointless, as that port is no longer reserved and can be allocated to something else. The only purpose of this exercise is to create a ServerSocket, so just create it.

user207421
  • 305,947
  • 44
  • 307
  • 483