2010-07-16 10 views
6

Ich verstehe, dass der folgende Code (vielleicht nicht sehr effizient) mit einem freien TCP-Port in Java herauszufinden:Die Suche nach zwei freien TCP-Ports

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

(Es gibt einige Fragen hier in SO - forexample) .

Was ich nicht verstehe ist, warum (oder ob) zwei aufeinanderfolgende Aufrufe dieser Methode garantiert zwei verschiedene Ports zurückgeben. Dies wird beispielsweise angenommen here (Suche nach den Aufrufen nach findFreePort Methode).

Ist das korrekt?

+0

Wenn es verwandte Fragen gibt, sollten Sie diese zitieren und mit ihnen verlinken. – Freiheit

+0

@Freiheit: Fertig – leonbloy

+0

Es ist nicht neu zugeordnet wegen SO_WAIT, einem Mechanismus, der entwickelt wurde, um zu umgehen, dass ein noch im Transit befindliches Paket von einem anderen Prozess empfangen würde.Wenn Sie standardmäßig einen TCP-Port schließen, wird er für die nächsten 2 Minuten nicht neu zugewiesen, damit diese verpufften Pakete geleert werden können. –

Antwort

5

In der Javadoc-Spezifikation, ich sehe keine Linie sagen, dass zwei sich aufeinander folgende Anrufe garantieren zwei verschiedene Häfen zurückzukehren ...

Da die Serversocket geschlossen ist, könnte ein zweiter Anruf den gleichen Port geben. Statistisch gesehen ist es unwahr- scheinlich, aber nicht unmöglich, denke ich.

Wenn Sie Ihre zwei ServerSocket öffnen, die Ports abrufen und dann Ihre beiden ServerSocket schließen, sind Sie dafür verantwortlich, zwei verschiedene Ports zu erhalten (da der erste nicht frei ist, wenn Sie den zweiten ServerSocket erstellen).

Beispiel Methode n verschiedene freie Ports zu erhalten:

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; 
} 
+0

Ja, ich hatte gerade fast genau die gleiche Methode programmiert :-) – leonbloy

+1

Es sollte angemerkt werden, dass selbst diese Lösung (und Noel M's) nicht 100% narrensicher ist, es gibt eine potentielle Race Condition. Nach diesem Methodenaufruf versucht der Aufrufer schließlich, diese verfügbaren Ports zu verwenden. Aber es könnte passieren, dass in der Zwischenzeit ein anderer Prozess es geöffnet hat. – leonbloy

0

Quellcode für ServerSocket- ist hier: http://kickjava.com/src/java/net/ServerSocket.java.htm

Ich bin nicht ganz zu sehen, wie sie bestimmt, ob der Port frei ist oder nicht, aber:

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

Also, wenn der erste Port zugeordnet ist, Selbst für Ihre Anwendung ist es nicht mehr kostenlos. Daher werden aufeinanderfolgende Aufrufe von ServerSocket diesen Port nicht wiederverwenden, wodurch zwei verschiedene Ports garantiert werden.

+0

Aber 'findFreePort' öffnet den Socket und schließt ihn sofort, also ist er theoretisch wieder verfügbar. – leonbloy

+0

Im Code ist der Port zugewiesen, aber die Methode "close()" weist diesen Port nicht zu. Anschließend kann es erneut verwendet werden (z. B. durch einen anderen ServerSocket). Also, ich denke, ein anderer Aufruf dieser Methode könnte die gleiche Portnummer geben. –

2

Eine Möglichkeit, zwei unterschiedliche Portnummern zu erhalten:

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

    socket1.close(); 
    socket2.close(); 
0

Es ist so effizient wie das Betriebssystem es machen kann. Es ist jedoch sinnlos, den ServerSocket unmittelbar danach zu schließen, da dieser Port nicht mehr reserviert ist und etwas anderem zugewiesen werden kann. Der einzige Zweck dieser Übung besteht darin, einen ServerSocket zu erstellen, also erstellen Sie ihn einfach.

0

Hier ist eine Klasse, die ich verwendet habe, um mehrere freie Ports zu finden. Es bietet die Flexibilität, einzelne Ports im Fluss einer komplexen Logik zuzuordnen (d. H. Wenn die Anzahl der benötigten Ports keine einfache Zahl ist, sondern von komplexer Logik abhängt). Es garantiert weiterhin, dass alle Ports, die Sie anfordern, kostenlos und eindeutig sind (solange Sie dieselbe Instanz dieser Klasse verwenden, um alle Ports zu erhalten).

Der Weg, um diese Klasse zu verwenden, wäre also eine Instanz zu erstellen. Führen Sie Ihren Code aus, um die gewünschten Ports für die Verwendung dieser Instanz zuzuordnen. Sobald Sie alle Ports gebunden haben, können Sie diese Instanz entsorgen und beim nächsten Mal eine neue verwenden.

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; 
} 

} 
+0

wo ist das findFreePort(); Methode. @Kris – Roster

+0

Es ist genau dort, das erste Mitglied der PortFinder-Klasse. Vielleicht verwechselte ich die Dinge mit der ungewöhnlichen Anordnung, sie vor die Felddeklaration zu stellen. – Kris

Verwandte Themen