2010-04-20 36 views
149

Quiero iniciar un servidor que escuche un puerto. Puedo especificar el puerto explícitamente y funciona. Pero me gustaría encontrar un puerto de forma automática. En este sentido, tengo dos preguntas.¿Cómo encontrar un puerto disponible?

  1. ¿En qué rango de números de puerto debo buscar? (Utilicé los puertos 12345, 12346 y 12347 y estuvo bien).

  2. ¿Cómo puedo saber si un puerto determinado no está ocupado por otro software?

Respuesta

219

Si no le molesta el puerto utilizado, especifique un puerto de 0 en ServerSocket constructor y escuchará en cualquier puerto libre.

ServerSocket s = new ServerSocket(0); 
System.out.println("listening on port: " + s.getLocalPort()); 

Si desea utilizar un conjunto específico de puertos, la forma más fácil es probablemente recorrerlos hasta que funcione. Algo como esto:

public ServerSocket create(int[] ports) throws IOException { 
    for (int port : ports) { 
     try { 
      return new ServerSocket(port); 
     } catch (IOException ex) { 
      continue; // try next port 
     } 
    } 

    // if the program gets here, no port in the range was found 
    throw new IOException("no free port found"); 
} 

Podría utilizarse como tal:

try { 
    ServerSocket s = create(new int[] { 3843, 4584, 4843 }); 
    System.out.println("listening on port: " + s.getLocalPort()); 
} catch (IOException ex) { 
    System.err.println("no available ports"); 
} 
+1

Al usar el nuevo ServerSocket (0), ¡se debe tener cuidado para cerrarlo! Basado en http: // javasourcecode.org/html/open-source/eclipse/eclipse-3.5.2/org/eclipse/jdt/launching/SocketUtil.java.html, ligeramente adaptado en mi https://gist.github.com/3429822 – vorburger

+7

@vorburger, doing de esa manera es propenso a las condiciones de carrera. Es mejor simplemente escuchar en el socket del servidor de inmediato, en lugar de abrirlo para encontrar un puerto libre, cerrarlo de nuevo, y luego abrir uno nuevamente en el puerto libre (para entonces hay una pequeña posibilidad de que algo más esté escuchando en ese momento). port.) –

+4

estuvo de acuerdo, pero depende del caso de uso exacto: en mi caso necesitaba encontrar un número de puerto libre para entregarlo en alguna API (digamos un arrancador Jetty integrado, para pruebas) - la API respectiva quiere un número de socket - no un socket de servidor ya abierto. Entonces eso depende. – vorburger

2

Si su servidor se inicia, entonces ese socket no se usó.

EDITAR

Algo así como:

ServerSocket s = null ; 

try { 
    s = new ServerSocket(0); 
} catch(IOException ioe){ 
    for(int i = START; i < END ; i++) try { 
     s = new ServerSocket(i); 
    } catch(IOException ioe){} 
} 
// At this point if s is null we are helpless 
if(s == null) { 
    throw new IOException(
     Strings.format("Unable to open server in port range(%d-%d)",START,END)); 
} 
+0

no hacer Sé quién te votó por el voto negativo, pero te voté de nuevo. Puede configurar una función recursiva para intentar configurar ServerSocket, y si obtiene una IOException (o lo que sea), intente nuevamente hasta que obtenga un puerto. – jonescb

+0

Creo que es mejor comprobar si hay un puerto disponible y luego tratar de comenzar a escuchar este puerto. Parece que no es elegante comenzar algo y luego descubrir que hay algún problema y luego tratar de resolver estos problemas. – Roman

+2

@ Roman bien, sí, eso sería mejor, excepto por el hecho de que no hay un método para saber si hay un puerto disponible. Si 'nuevo ServerSocket (0)' no funciona para usted, la alternativa es esta. Creo que hay un 85% de posibilidades de que termines usando mi sugerencia. – OscarRyz

21

Según Wikipedia, se debe utilizar puertos 49152 a 65535 si no necesita un puerto 'conocida'.

AFAIK la única manera de determinar si un puerto está en uso es tratar de abrirlo.

+0

+1. Como Wikipedia no siempre es la fuente de verdad/hechos absolutos, pensé que podría ser útil tener en cuenta que la referencia para esa página de Wikipedia proviene de "Autoridad de números asignados de Internet (IANA)" [Nombre del servicio y número de puerto del protocolo de transporte Página de registro (https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml)] ", basada en [RFC 6335 - Sección 6] (https: // tools.ietf.org/html/rfc6335#section-6) (es decir, referencia "sólida" en este caso! :)). – OzgurH

48

Si pasa 0 como el número de puerto al constructor de ServerSocket, asignará un puerto para usted.

+0

Sí, creo que es la solución más elegante pero, por alguna razón, no funciona en mi caso. Pero aún necesito averiguar qué es exactamente lo que está mal. – Roman

+0

@Roman, publique su código y descubramos – OscarRyz

+1

@Roman: ¿Por qué no funciona? Actualice su pregunta para incluir esto (o las personas lo seguirán sugiriendo) y explique por qué esta solución falla para usted. – FrustratedWithFormsDesigner

10

El Eclipse SDK contiene una clase SocketUtil, que hace lo que quiere. Puede echarle un vistazo al git source code.

+1

Al mirar el código de Eclipse, hacen lo mismo que la respuesta de Graham Edgecombe – KevinL

2

Puede que no te ayude demasiado, pero en mi máquina (Ubuntu) tengo un archivo/etc/services en el que se incluyen al menos los puertos utilizados/reservados por algunas de las aplicaciones. Estos son los puertos estándar para esas aplicaciones.

No hay garantías de que se estén ejecutando, solo los puertos predeterminados que usan estas aplicaciones (por lo tanto, no debe usarlos si es posible).

Hay un poco más de 500 puertos definidos, aproximadamente la mitad de UDP y la mitad de TCP.

Los archivos están hechos usando información de IANA, vea IANA Assigned port numbers.

+0

hay una lista similar (y más completa, IIRC) que viene como parte de nmap. +1 – rmeador

5

Esto funciona para mí en Java 6

ServerSocket serverSocket = new ServerSocket(0); 
    System.out.println("listening on port " + serverSocket.getLocalPort()); 
4

Si desea crear su propio servidor usando un ServerSocket, sólo puede tenerlo seleccionar un puerto libre para usted:

ServerSocket serverSocket = new ServerSocket(0); 
    int port = serverSocket.getLocalPort(); 

Otros las implementaciones de servidor suelen tener un soporte similar. embarcadero por ejemplo, recoge un puerto libre a menos que se establezca explícitamente:

Server server = new Server(); 
    ServerConnector connector = new ServerConnector(server); 
    // don't call: connector.setPort(port); 
    server.addConnector(connector); 
    server.start(); 
    int port = connector.getLocalPort(); 
24

A partir de Java 1.7 se puede utilizar try-con-recursos como este:

private Integer findRandomOpenPortOnAllLocalInterfaces() throws IOException { 
    try (
     ServerSocket socket = new ServerSocket(0); 
    ) { 
     return socket.getLocalPort(); 

    } 
    } 

Si necesita encontrar un puerto abierto en una interfaz específica, consulte ServerSocket documentación para constructores alternativos.

Advertencia: Cualquier código utilizando el número de puerto devuelto por este método está sujeto a una condición de carrera - un proceso/hilo diferente puede unirse al mismo puerto inmediatamente después de cerrar la instancia ServerSocket.

+0

Esto podría no funcionar si no configuras 'SO_REUSEADDR'. Y hay una condición de carrera, pero es difícil arreglar eso. –

+0

Esto podría no funcionar si posteriormente intentas abrir * otro * 'ServerSocket' con el mismo número de puerto, ya que podría haberse tomado mientras tanto. Por qué no solo devuelve el 'ServerSocket' real en lugar de cerrarlo sigue siendo un misterio. – EJP

4

Recientemente he lanzado una pequeña biblioteca para hacer justamente eso con las pruebas en mente. Maven dependencia es:

<dependency> 
    <groupId>me.alexpanov</groupId> 
    <artifactId>free-port-finder</artifactId> 
    <version>1.0</version> 
</dependency> 

Una vez instalado, los números de puerto libre puede obtenerse a través de:

int port = FreePortFinder.findFreeLocalPort(); 
15

Si necesita en gama uso:

public int nextFreePort(int from, int to) { 
    int port = randPort(from, to); 
    while (true) { 
     if (isLocalPortFree(port)) { 
      return port; 
     } else { 
      port = ThreadLocalRandom.current().nextInt(from, to); 
     } 
    } 
} 

private boolean isLocalPortFree(int port) { 
    try { 
     new ServerSocket(port).close(); 
     return true; 
    } catch (IOException e) { 
     return false; 
    } 
} 
+0

se preguntaba cómo verificar un puerto, luego desvincularse de él. Gracias SergeyB! –

+2

Si cada puerto en el rango [de, a) está en uso, este código se repetirá infinitamente (o al menos hasta que uno de esos puertos sea libre). Si realiza un escaneo secuencial en lugar de elegir puertos en el rango al azar, puede evitar esta posibilidad (solo haga una excepción cuando llegue al final del rango sin encontrar un puerto libre). Si realmente necesita elegir puertos al azar, necesita un conjunto para realizar un seguimiento de los puertos que ha intentado hasta el momento, y luego generar un error cuando el tamaño de ese conjunto es igual a - desde. –

Cuestiones relacionadas