[java] 소켓 : Java를 사용하여 포트 가용성 검색

Java를 사용하여 주어진 시스템에서 포트의 가용성을 프로그래밍 방식으로 어떻게 결정합니까?

즉, 포트 번호가 주어지면 이미 사용 중인지 여부를 결정합니까?.



답변

이것은 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;
}

포트가 UDP 및 TCP에서 사용 가능한지 확인하기 위해 DatagramSocket도 확인하고 있습니다.

도움이 되었기를 바랍니다.


답변

Java 7의 경우보다 간결한 코드를 위해 try-with-resource를 사용할 수 있습니다.

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


답변

Java 7부터 David Santamaria의 답변 이 더 이상 안정적으로 작동하지 않는 것 같습니다. 그러나 여전히 안정적으로 소켓을 사용하여 연결을 테스트 할 수있는 것 같습니다.

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


답변

성능에 너무 관심이 없다면 항상 ServerSocket 클래스를 사용하여 포트에서 수신을 시도 할 수 있습니다. 예외 확률이 발생하면 사용중인 것입니다.

public static boolean isAvailable(int portNr) {
  boolean portFree;
  try (var ignored = new ServerSocket(portNr)) {
      portFree = true;
  } catch (IOException e) {
      portFree = false;
  }
  return portFree;
}

편집 : 당신이하려는 모든 것이 무료 포트를 선택하면 new ServerSocket(0)당신을 위해 하나를 찾을 것입니다.


답변

다음 솔루션은 SocketUtils에서 영감을 얻었습니다. Spring-core (Apache 라이센스) 구현에서 .

Socket(...)이를 사용 하는 다른 솔루션에 비해 매우 빠릅니다 (1 초 이내에 1000 개의 TCP 포트 테스트).

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


답변

try / catch 소켓 기반 솔루션은 정확한 결과를 얻지 못할 수 있습니다 (소켓 주소는 “localhost”이고 경우에 따라 포트는 루프백 인터페이스가 아닌 “점유”될 수 있으며 적어도 Windows에서는이 테스트가 실패하는 것을 보았습니다. 사용 가능한 것으로 잘못 선언 된 prot).

SIGAR 라는 멋진 라이브러리가 있습니다 . 다음 코드로 연결할 수 있습니다.

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;


답변

David Santamaria가 지적한 답변 정리 :

/**
 * Check to see if a port is available.
 *
 * @param port
 *            the port to check for availability.
 */
public static boolean isPortAvailable(int port) {
    try (var ss = new ServerSocket(port); var ds = new DatagramSocket(port)) {
        return true;
    } catch (IOException e) {
        return false;
    }
}

이것은 여전히 ​​David Santamaria의 답변에 대한 의견에서 user207421이 지적한 경쟁 조건의 영향을받습니다 (이 메서드가 ServerSocketand를 닫고 DatagramSocket반환 한 후에 뭔가 포트를 가져올 수 있음 ).