2010-07-16 14 views
6

Je comprends que le code suivant peut (peut-être pas très efficace) trouver un port TCP libre en Java:Trouver deux ports tcp libres

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

(Il y a ici SO quelques questions connexes - forexample) . Ce que je ne comprends pas, c'est pourquoi (ou si) deux appels successifs à cette méthode sont garantis pour retourner deux ports différents. Ceci est supposé, par exemple, here (recherche des appels à la méthode findFreePort).

Est-ce correct?

+0

Si vous avez des questions connexes, vous devez les citer et les lier. – Freiheit

+0

@Freiheit: Fait – leonbloy

+0

Il n'est pas réaffecté à cause de SO_WAIT, un mécanisme conçu pour contourner le fait qu'un paquet encore en transit serait reçu par un autre processus.Par défaut, si vous fermez un port TCP, il n'est pas réaffecté pendant les 2 minutes suivantes pour permettre à ces paquets persistants de se vider. –

Répondre

5

Dans la spécification Javadoc, je ne vois pas une ligne disant que deux appels successifs est garanti retourner deux ports différents ...

Depuis le ServerSocket est fermé, un second appel pourrait donner le même port. Statistiquement, c'est improbable mais pas impossible je pense. Si vous ouvrez vos deux ServerSocket, obtenez les ports, puis fermez vos deux ServerSocket, vous êtes guidé pour obtenir deux ports différents (puisque le premier n'est pas libre lorsque vous créez le second ServerSocket).

méthode Exemple pour obtenir n différents ports libres:

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

Oui, j'avais juste codé presque exactement la même méthode :-) – leonbloy

+1

Il est à noter que même cette solution (et celle de Noel M) n'est pas à 100% infaillible, il existe une condition de concurrence potentielle. Après cet appel de méthode, l'appelant essaiera éventuellement d'utiliser ces ports disponibles. Mais il pourrait arriver qu'en attendant, un autre processus l'ait ouvert. – leonbloy

0

code source pour ServerSocket est ici: http://kickjava.com/src/java/net/ServerSocket.java.htm

Je ne suis pas tout à fait de voir comment il détermine si le port est libre ou non, mais:

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

Donc, une fois le premier port est alloué, même pour votre application, ce n'est plus gratuit. Les appels successifs à ServerSocket ne réutiliseront donc pas ce port, garantissant ainsi deux ports différents.

+0

Mais 'findFreePort' ouvre le socket et le ferme immédiatement, donc en théorie est de nouveau disponible. – leonbloy

+0

Dans le code, le port est alloué, mais la méthode "close()" désalloue ce port. Ensuite, il peut être réutilisé (par un autre ServerSocket, par exemple). Donc, je pense qu'un autre appel à cette méthode pourrait donner le même numéro de port. –

2

Une façon d'obtenir deux numéros de port différents:

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

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

Il est aussi efficace que le système d'exploitation peut le faire. Cependant, fermer ServerSocket immédiatement après est inutile, car ce port n'est plus réservé et peut être affecté à autre chose. Le seul but de cet exercice est de créer un ServerSocket, il suffit de le créer.

0

Voici une classe que j'ai utilisée pour trouver plusieurs ports libres. Il offre la flexibilité d'allouer des ports individuels dans le flux d'une logique complexe (c'est-à-dire lorsque le nombre de ports dont vous aurez besoin n'est peut-être pas un nombre simple mais dépend d'une logique complexe). Il garantit toujours que tous les ports que vous demandez gratuitement et unique (tant que vous utilisez la même instance de cette classe pour obtenir tous les ports). Donc, la façon d'utiliser cette classe serait de créer une instance. Exécutez votre code pour faire ce que vous voulez allouer des ports pour utiliser cette instance. Ensuite, une fois que vous avez lié tous les ports, vous pouvez disposer de cette instance et en utiliser une nouvelle la fois suivante.

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

où est le findFreePort(); méthode. @Kris – Roster

+0

C'est juste là, le premier membre de la classe PortFinder. Peut-être que j'ai confondu les choses par l'ordre inhabituel de le mettre avant la déclaration sur le terrain. – Kris