2009-01-12 13 views
101

¿Cómo puedo determinar mediante programación la disponibilidad de un puerto en una máquina determinada utilizando Java?Enchufes: descubra la disponibilidad del puerto con Java

i.e dado un número de puerto, determinar si ya se está utilizando o no ?.

+2

Aunque esta pregunta es acerca de cómo saber si un determinado puerto ya está en uso, puede haber aterrizado aquí tratando de encontrar una manera de obtener un número de puerto gratuito, que http://stackoverflow.com/questions/2675362/how-to-find-an-available-port (con un enlace a mi https: // gist .github.com/3429822) cubre mejor. – vorburger

+0

¿Para qué? Si solo desea encontrar un socket vacante para escuchar, solo especifique cero. Cualquier técnica de exploración se hace responsable de los problemas de sincronización-ventana:. El puerto puede ser vacante cuando se escanea y ocupado cuando se va a reclamar en – EJP

Respuesta

30

Si no le preocupa el rendimiento, siempre puede intentar escuchar en un puerto utilizando la clase ServerSocket. Si arroja una excepción de excepción, se está utilizando.

boolean portTaken = false; 
    ServerSocket socket = null; 
    try { 
     socket = new ServerSocket(_port); 
    } catch (IOException e) { 
     portTaken = true; 
    } finally { 
     if (socket != null) 
      try { 
       socket.close(); 
      } catch (IOException e) { /* e.printStackTrace(); */ } 
} 

EDIT: Si todo lo que estamos tratando de hacer es seleccionar un puerto libre entonces new SocketServer(0) va a encontrar uno para usted.

+0

Uso finalmente para la limpieza (try {...} catch {...} finally {if (! socket = null) Socket.close();} –

+0

también puede establecer "portTaken = (socket == null);". al final en lugar de hacerlo en la captura –

+0

Esto intenta obligar a la toma de todos (0.0.0.0) interfaces. se pueden utilizar direcciones explícitas para comprobar puertos específicos en direcciones específicas. ver http://java.sun.com/j2se/1.4.2/docs/api/java/net/ServerSocket.html#ServerSocket (int,% 20int,% 20java.net.InetAddress) – cletus

82

Este es el implementation procedente del proyecto Apache camel:

/** 
* Checks to see if a specific port is available. 
* 
* @param port the port to check for availability 
*/ 
public static boolean available(int port) { 
    if (port < MIN_PORT_NUMBER || port > MAX_PORT_NUMBER) { 
     throw new IllegalArgumentException("Invalid start port: " + port); 
    } 

    ServerSocket ss = null; 
    DatagramSocket ds = null; 
    try { 
     ss = new ServerSocket(port); 
     ss.setReuseAddress(true); 
     ds = new DatagramSocket(port); 
     ds.setReuseAddress(true); 
     return true; 
    } catch (IOException e) { 
    } finally { 
     if (ds != null) { 
      ds.close(); 
     } 

     if (ss != null) { 
      try { 
       ss.close(); 
      } catch (IOException e) { 
       /* should not be thrown */ 
      } 
     } 
    } 

    return false; 
} 

están comprobando la DatagramSocket así comprobar si el puerto está disponible en UDP y TCP.

Espero que esto ayude.

+5

Una buena variante de esto si tiene MINA es AvailablePortFinder.getNextAvailable (1024), que se obtiene el siguiente puerto no privilegiado. –

+9

Esto no atrapa todo sin embargo. Me ha picado un nginx en ejecución en TCP 8000, mientras que la rutina anterior informa que 8000 está disponible. No tengo idea de por qué, sospecho que nginx hace algunas cosas furtivas (esto es en OS X). La solución para mí es hacer lo anterior y también abrir un nuevo Socket ("localhost", puerto) y luego devolver falso si no obtenemos una excepción. ¿Pensamientos? –

+0

que he tenido el mismo problema con OS X. – OmerGertel

0

En mi caso, me ayudó a probar y conectarme al puerto; si el servicio ya está presente, respondería.

try { 
     log.debug("{}: Checking if port open by trying to connect as a client", portNumber); 
     Socket sock = new Socket("localhost", portNumber);   
     sock.close(); 
     log.debug("{}: Someone responding on port - seems not open", portNumber); 
     return false; 
    } catch (Exception e) {   
     if (e.getMessage().contains("refused")) { 
      return true; 
    } 
     log.error("Troubles checking if port is open", e); 
     throw new RuntimeException(e);    
    } 
+1

No es lo que se pidió. – EJP

31

Parece que a partir de Java 7, David Santamaria's answer no funciona de forma fiable más. Sin embargo, parece que todavía se puede usar un Socket de manera confiable para probar la conexión.

private static boolean available(int port) { 
    System.out.println("--------------Testing port " + port); 
    Socket s = null; 
    try { 
     s = new Socket("localhost", port); 

     // If the code makes it this far without an exception it means 
     // something is using the port and has responded. 
     System.out.println("--------------Port " + port + " is not available"); 
     return false; 
    } catch (IOException e) { 
     System.out.println("--------------Port " + port + " is available"); 
     return true; 
    } finally { 
     if(s != null){ 
      try { 
       s.close(); 
      } catch (IOException e) { 
       throw new RuntimeException("You should handle this error." , e); 
      } 
     } 
    } 
} 
+1

Probado ambas soluciones y puedo confirmar TwentyMiles es correcto – betaman

+0

Quiero comprobar si un servidor proxy está disponible para las marcas llaman en su nombre. – Dejell

+1

@ La respuesta de DavidSantamaria nunca funcionó. Nada que ver con Java 7. – EJP

35

Para Java 7 puede utilizar try-con-recurso para más código compacto:

private static boolean available(int port) { 
    try (Socket ignored = new Socket("localhost", port)) { 
     return false; 
    } catch (IOException ignored) { 
     return true; 
    } 
} 
+6

Esto no prueba si el puerto está disponible. Comprueba si está en estado LISTEN, si la dirección IP es alcanzable, etc. – EJP

+0

Además, esta prueba es bastante lenta (casi un segundo por puerto). – JMax

3

soluciones basadas en la toma de try/catch, podría no dar resultados precisos (la dirección de socket es "localhost "y en algunos casos el puerto podría estar" ocupado "no por la interfaz de bucle invertido y al menos en Windows he visto que esta prueba falla, es decir, el prot declarado falsamente como disponible).

Hay una biblioteca fresca llamado SIGAR, el siguiente código puede liarte:

Sigar sigar = new Sigar(); 
int flags = NetFlags.CONN_TCP | NetFlags.CONN_SERVER | NetFlags.CONN_CLIENT;    NetConnection[] netConnectionList = sigar.getNetConnectionList(flags); 
for (NetConnection netConnection : netConnectionList) { 
    if (netConnection.getLocalPort() == port) 
     return false; 
} 
return true; 
+0

Obtengo: "no sigar-x86-winnt.dll en java.library.ruta " Desafortunadamente, requiere la descarga de un dll adicional que no es realmente viable en el entorno empresarial (no tengo control sobre el sistema CI). Tan malo ... Gracias de todos modos. – uthomas

+0

@uthomas Supongo que todavía tiene el control de su aplicación paquete de despliegue, si este es el caso, siempre puede proporcionar DLL/SOs de tiempo de ejecución nativo de Sigar cerca de sus JAR y establecer la ruta JAVA lib de forma pragmática (a través de hack simple puede influir incluso después de que la JVM haya lanzado su aplicación) –

0

He intentado algo como esto y funcionó muy bien conmigo

  Socket Skt; 
      String host = "localhost"; 
      int i = 8983; // port no. 

       try { 
        System.out.println("Looking for "+ i); 
        Skt = new Socket(host, i); 
        System.out.println("There is a Server on port " 
        + i + " of " + host); 
       } 
       catch (UnknownHostException e) { 
        System.out.println("Exception occured"+ e); 

       } 
       catch (IOException e) { 
        System.out.println("port is not used"); 

       } 
+1

se solicitó. – EJP

+0

Y también una fuga de socket – EJP

-1

En mi caso Tuve que usar la clase DatagramSocket.

boolean isPortOccupied(int port) { 
    DatagramSocket sock = null; 
    try { 
     sock = new DatagramSocket(port); 
     sock.close(); 
     return false; 
    } catch (BindException ignored) { 
     return true; 
    } catch (SocketException ex) { 
     System.out.println(ex); 
     return true; 
    } 
} 

No se olvide de importar primera

import java.net.DatagramSocket; 
import java.net.BindException; 
import java.net.SocketException; 
+0

Esto funciona para puertos UDP. La pregunta parece ser sobre puertos TCP. – EJP

1

La siguiente solución se inspira en la implementación de SocketUtils Primavera-núcleo (licencia Apache).

En comparación con otras soluciones que utilizan Socket(...) es bastante rápido (pruebas de 1000 puertos TCP en menos de un segundo):

public static boolean isTcpPortAvailable(int port) { 
    try (ServerSocket serverSocket = new ServerSocket()) { 
     // setReuseAddress(false) is required only on OSX, 
     // otherwise the code will not work correctly on that platform   
     serverSocket.setReuseAddress(false); 
     serverSocket.bind(new InetSocketAddress(InetAddress.getByName("localhost"), port), 1); 
     return true; 
    } catch (Exception ex) { 
     return false; 
    } 
}  
Cuestiones relacionadas