28 Mart 2023 Salı

ServerSocket Sınıfı İçin Boş Port Bulma

Giriş
İki yöntem var
1. Rastgele (Ephemeral) port kullanılır. İşletim sistemi boş bir port kullanmayı garanti eder
2. Deneyerek kullanılmayan port bulunur

1. Rastgele (Ephemeral) Port Kullanma
Örnek
Şöyle yaparız. Burada bind() çağrısına 0 değeri veriliyor
ServerSocket serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
// Bind to an ephemeral port
serverSocket.bind(new InetSocketAddress(0));
InetSocketAddres localAddress = (InetSocketAddress) serverSocket.getLocalSocketAddress();
Örnek
Şöyle yaparız. Burada sonradan bind() yerine direkt constructor içine 0 değeri veriliyor. spawn() yeni bir thread başlatıyor. uncheckRun() ise fırlatılan exception'ları @SneakThrows gibi yapıyor
 try (ServerSocket socket = new ServerSocket(0) ) {
  int localPort = socket.getLocalPort();
  ...
}
2. Portları Deneyerek Bulma
Bir yazı burada
Örnek
Şöyle yaparız. Bu kodu Spring'in TestSocketUtils sınıfından devşirdim. Rastgele bir port bulmayı 5 kere deniyor
import static org.junit.Assert.fail;

public class TestSocketUtils {
  static final int PORT_RANGE_MIN = 1024;
  static final int PORT_RANGE_MAX = 65535;
  private static final int PORT_RANGE = PORT_RANGE_MAX - PORT_RANGE_MIN + 1;
  private static final int MAX_ATTEMPTS = 5;
  private static final Random random = new Random(System.nanoTime());
  private static final TestSocketUtils INSTANCE = new TestSocketUtils();

  public static int findAvailableTcpPort() {
    return INSTANCE.findAvailableTcpPortInternal();
  }

  int findAvailableTcpPortInternal() {
    int candidatePort;
    int attemptCounter = 0;
    do {
      if (++attemptCounter > MAX_ATTEMPTS) {
        String message = "Could not find an available TCP port";
        fail(message);
      }
      candidatePort = PORT_RANGE_MIN + random.nextInt(PORT_RANGE);
    }
    while (!isPortAvailable(candidatePort));

    return candidatePort;
  }
}
port'u kontrol eden kod şöyle. Burada createServerSocket() çağrısına backlog olarak 1 geçiliyor. Yani sadece 1 client bekleyebilir
boolean isPortAvailable(int port) {
  try {
    ServerSocket serverSocket = ServerSocketFactory.getDefault()
      .createServerSocket(port, 1, InetAddress.getByName("localhost"));
    serverSocket.close();
    return true;
  } catch (Exception ex) {
    return false;
  }
}
Örnek
Bir başka örnek burada. basePort numarasından başlayarak belirtilen sayı kadar boş port bulmaya çalışıyor. Burada hem TCP hem de UDP portlarına bakıyor. Biraz gereksiz olmuş
public static int getAvailablePort(int basePort) {
  return getAvailablePorts(basePort, 1).get(0);
}

public static List<Integer> getAvailablePorts(int basePort, int portCount) {
  List<Integer> availablePorts = new ArrayList<>();
  int port = basePort;
  for (int i = 0; i < portCount; i++) {
    while (!isPortAvailable(port)) {
      port++;
    }
    availablePorts.add(port++);
  }
  return availablePorts;
}

public static boolean isPortAvailable(int 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) {
    return false;
  } finally {
    if (ds != null) {
      ds.close();
    }
    try {
      if (ss != null) {
        ss.close();
      }
    } catch (IOException e) {
     ignore(e);
    }
  }
}


Hiç yorum yok:

Yorum Gönder