Escaneo de Redes y Comunicación TCP/IP

Tarea de Laboratorio:

Explorar el rango de direcciones IP XXX.XXX.XXX.* (por ejemplo, 192.168.236.* , el rango específico será comunicado durante la clase) en busca de servidores intermedios en el puerto 6060 y completar las tareas asignadas.

Sugerencia: Durante el proceso de escaneo, primero puede utilizar un programa de escaneo de hosts para determinar qué direcciones en el rango son alcanzablees, luego usar un programa de escaneo de puertos para verificar si el puerto 6060 está abierto en estos hosts activos. Una vez enconrtado el host correcto, utilice el cliente multihilo del tema 3 para establecer una conexión TCP y seguir las instrucciones para completar la tarea. Nota: Si considera tedioso escanear hosts y puertos individualmente, puede optar por completar primero el ejercicio extendido, combinando el escaneo de hosts y puertos para encontrar el host correcto.

1. Identificación del Segmento de Red

Se determina que el segmento de red es 192.168.233.*

2. Escaneo de Hosts Activos

package red;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class ExploradorHostsFX extends Application {
  private TextField campoInicioIP; // Campo de entrada para IP inicial
  private TextField campoFinIP;   // Campo de entrada para IP final
  private TextArea areaResultado;  // Área de resultados (solo muestra hosts activos)
  private Button btnEscaneo;         // Botón de escaneo
  private Button btnDetener;         // Botón de detención
  private final AtomicBoolean escaneando = new AtomicBoolean(false); // Indicador de estado
  private final List<thread> hilosEscaneo = new ArrayList<>(); // Lista de hilos de escaneo

  @Override
  public void start(Stage primaryStage) {
    primaryStage.setTitle("Explorador de Hosts");

    // Diseño de la interfaz, basado en la estructura de la ventana de exploración de hosts
    BorderPane root = new BorderPane();
    root.setPadding(new Insets(15));

    // Área de entrada (IP inicial, IP final)
    VBox cajaEntrada = new VBox(10);
    cajaEntrada.setPadding(new Insets(10));
    cajaEntrada.setAlignment(Pos.CENTER);

    HBox cajaInicioIP = new HBox(10);
    Label etiquetaInicioIP = new Label("Dirección inicial:");
    campoInicioIP = new TextField("192.168.0.140"); // Ejemplo de IP inicial
    campoInicioIP.setPrefWidth(150);
    cajaInicioIP.getChildren().addAll(etiquetaInicioIP, campoInicioIP);

    HBox cajaFinIP = new HBox(10);
    Label etiquetaFinIP = new Label("Dirección final:");
    campoFinIP = new TextField("192.168.1.1"); // Ejemplo de IP final
    campoFinIP.setPrefWidth(150);
    cajaFinIP.getChildren().addAll(etiquetaFinIP, campoFinIP);

    cajaEntrada.getChildren().addAll(cajaInicioIP, cajaFinIP);

    // Área de botones
    HBox cajaBotones = new HBox(10);
    cajaBotones.setPadding(new Insets(10));
    cajaBotones.setAlignment(Pos.CENTER);

    btnEscaneo = new Button("Explorar Hosts");
    btnEscaneo.setPrefWidth(100);
    btnDetener = new Button("Detener Escaneo");
    btnDetener.setPrefWidth(100);
    btnDetener.setDisable(true); // Inhabilitado inicialmente

    cajaBotones.getChildren().addAll(btnEscaneo, btnDetener);

    // Área de resultados (solo muestra IPs de hosts activos)
    areaResultado = new TextArea();
    areaResultado.setEditable(false);
    areaResultado.setWrapText(true);

    // Ensamblaje de la interfaz
    VBox cajaSuperior = new VBox(15);
    cajaSuperior.getChildren().addAll(cajaEntrada, cajaBotones);
    root.setTop(cajaSuperior);
    root.setCenter(areaResultado);

    // Asignación de eventos
    btnEscaneo.setOnAction(e -> iniciarEscaneo());
    btnDetener.setOnAction(e -> detenerEscaneo());

    // Configuración del escenario
    Scene scene = new Scene(root, 500, 400);
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  /**
   * Iniciar escaneo: solo detecta y muestra IPs de hosts activos
   */
  private void iniciarEscaneo() {
    // Detener hilos de escaneo anteriores para evitar resultados mezclados
    detenerEscaneo();

    String inicioIP = campoInicioIP.getText().trim();
    String finIP = campoFinIP.getText().trim();

    // Validar formato de IP (validación simplificada)
    if (!esIPValida(inicioIP) || !esIPValida(finIP)) {
      areaResultado.appendText("Error: ¡Formato de dirección IP inválido!\n");
      return;
    }

    // Convertir IP a long para implementar la eficiente iteración de rangos
    long inicioLong = ipALong(inicioIP);
    long finLong = ipALong(finIP);

    if (inicioLong > finLong) {
      areaResultado.appendText("Error: ¡La IP inicial no puede ser mayor que la IP final!\n");
      return;
    }

    // Inicializar estado de escaneo
    escaneando.set(true);
    btnEscaneo.setDisable(true);
    btnDetener.setDisable(false);
    areaResultado.clear();
    areaResultado.appendText("Iniciando escaneo de rango IP: " + inicioIP + " - " + finIP + "\n");
    areaResultado.appendText("==============================\n");
    areaResultado.appendText("Lista de hosts activos:\n");

    // Iniciar hilo de escaneo (iteración en un solo hilo, extensible a múltiples)
    Thread hiloEscaneo = new Thread(() -> {
      for (long ipLong = inicioLong; ipLong <= finLong && escaneando.get(); ipLong++) {
        String ip = longAIP(ipLong);
        try {
          InetAddress addr = InetAddress.getByName(ip);
          // Solo mostrar IP si el host está activo
          if (addr.isReachable(500)) { // Tiempo de espera 500ms
            String mensajeHostActivo = "→ " + ip + " está activo!\n";
            Platform.runLater(() -> areaResultado.appendText(mensajeHostActivo));
          }
        } catch (UnknownHostException e) {
          // IP inválida, no mostrar
        } catch (Exception e) {
          // Excepción durante escaneo, no mostrar
        }
      }

      // Al finalizar el escaneo, restablecer estado
      Platform.runLater(() -> {
        areaResultado.appendText("==============================\n");
        areaResultado.appendText("¡Escaneo completado!\n");
        escaneando.set(false);
        btnEscaneo.setDisable(false);
        btnDetener.setDisable(true);
      });
    });

    hilosEscaneo.add(hiloEscaneo);
    hiloEscaneo.start();
  }

  /**
   * Detener escaneo: interrumpe todos los hilos de escaneo
   */
  private void detenerEscaneo() {
    if (escaneando.get()) {
      escaneando.set(false);
      for (Thread hilo : hilosEscaneo) {
        if (hilo.isAlive()) {
          hilo.interrupt();
        }
      }
      hilosEscaneo.clear();
      areaResultado.appendText("\n¡Escaneo detenido!\n");
    }
    btnEscaneo.setDisable(false);
    btnDetener.setDisable(true);
  }

  /**
   * Conversión de dirección IP a long, implementando el algoritmo central
   */
  public long ipALong(String ip) {
    String[] arregloIP = ip.split("\\.");
    long num = 0;
    for (int i = 0; i < arregloIP.length; i++) {
      long valorSeccion = Long.parseLong(arregloIP[i]);
      num = (valorSeccion << 8 * (3 - i)) | num;
    }
    return num;
  }

  /**
   * Conversión de long a dirección IP, soporte inverso para iteración de IPs
   */
  public String longAIP(long ipLong) {
    return ((ipLong >> 24) & 0xFF) + "." +
      ((ipLong >> 16) & 0xFF) + "." +
      ((ipLong >> 8) & 0xFF) + "." +
      (ipLong & 0xFF);
  }

  /**
   * Validación simplificada de formato de IP
   */
  private boolean esIPValida(String ip) {
    String regex = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$";
    return ip.matches(regex);
  }

  public static void main(String[] args) {
    launch(args);
  }
}</thread>

3. Escaneo de Puertos

Se puede copiar el resultado y pedirle a una IA que modifique el código original

package red;

import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class EscaneadorPuertos6060 {
  // Puerto objetivo: 6060
  private static final int PUERTO_OBJETIVO = 6060;
  // Tiempo de espera de conexión (milisegundos)
  private static final int ESPERA_CONEXION = 300;
  // Tamaño del pool de hilos: ajustado según número de hosts
  private static final int TAMANO_POOL = 10;
  // Contador de hosts escaneados (clase atómica para seguridad en hilos)
  private static final AtomicInteger contadorEscaneado = new AtomicInteger(0);
  // Lista de hosts con puerto 6060 abierto
  private static final List<string> hostsPuertoAbierto = new ArrayList<>();

  public static void main(String[] args) {
    // 1. Inicializar lista de IPs de hosts activos a escanear
    List<string> hostsActivos = inicializarHostsActivos();
    int totalHosts = hostsActivos.size();
    System.out.printf("=== Iniciando escaneo masivo de %d hosts activos en puerto 6060 ===%n", totalHosts);
    System.out.printf("Configuración de escaneo: espera %dms, hilos %d%n%n", ESPERA_CONEXION, TAMANO_POOL);

    // 2. Usar CountDownLatch para esperar a que todos los hilos de escaneo completen
    CountDownLatch latchFinal = new CountDownLatch(totalHosts);
    // Crear pool de hilos (evitar creación y destrucción frecuente para mejorar eficiencia)
    ExecutorService servicioEjecutor = Executors.newFixedThreadPool(TAMANO_POOL);

    // 3. Enviar tareas de escaneo al pool de hilos
    for (String host : hostsActivos) {
      servicioEjecutor.submit(() -> {
        try {
          // Detección rápida de puerto: lógica de "escaneo rápido" (Socket.connect con timeout)
          Socket socket = new Socket();
          socket.connect(new InetSocketAddress(host, PUERTO_OBJETIVO), ESPERA_CONEXION);
          // Conexión exitosa → puerto abierto, agregar a lista de resultados (seguro para hilos)
          synchronized (hostsPuertoAbierto) {
            hostsPuertoAbierto.add(host);
          }
          System.out.printf("✅ %s : puerto 6060 abierto%n", host);
          socket.close();
        } catch (Exception e) {
          // Conexión fallida/tiempo de espera → puerto cerrado (lógica: excepción indica puerto cerrado)
          System.out.printf("❌ %s : puerto 6060 cerrado/no alcanzable%n", host);
        } finally {
          // Después de escanear cada host, incrementar contador y actualizar progreso
          int actual = contadorEscaneado.incrementAndGet();
          System.out.printf("📊 Progreso de escaneo: %d/%d (%.1f%%)%n",
            actual, totalHosts, (actual * 100.0) / totalHosts);
          // Decrementar contador, marcar finalización de tarea actual
          latchFinal.countDown();
        }
      });
    }

    // 4. Esperar a que todos los hilos terminen, cerrar pool y mostrar resultados finales
    try {
      latchFinal.await(); // Hilo principal espera a que todos los hilos de escaneo terminen
      servicioEjecutor.shutdown(); // Cerrar pool de hilos
      System.out.printf("%n=== ¡Escaneo completado! Hosts escaneados: %d ===%n", totalHosts);
      System.out.printf("📋 Lista de hosts con puerto 6060 abierto (%d hosts):%n", hostsPuertoAbierto.size());
      if (hostsPuertoAbierto.isEmpty()) {
        System.out.println("   Ningún host con puerto 6060 abierto");
      } else {
        for (String host : hostsPuertoAbierto) {
          System.out.printf("   %s%n", host);
        }
      }
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      System.err.println("Escaneo interrumpido: " + e.getMessage());
    }
  }

  /**
   * Inicializar lista de IPs de hosts activos según requerimientos
   */
  private static List<string> inicializarHostsActivos() {
    List<string> hosts = new ArrayList<>();
    // Agregar todas las IPs de hosts activos requeridas
    hosts.add("192.168.233.31");
    hosts.add("192.168.233.32");
    hosts.add("192.168.233.34");
    hosts.add("192.168.233.88");
    hosts.add("192.168.233.89");
    hosts.add("192.168.233.125");
    hosts.add("192.168.233.127");
    hosts.add("192.168.233.129");
    hosts.add("192.168.233.130");
    hosts.add("192.168.233.131");
    hosts.add("192.168.233.132");
    hosts.add("192.168.233.133");
    hosts.add("192.168.233.134");
    hosts.add("192.168.233.135");
    hosts.add("192.168.233.136");
    hosts.add("192.168.233.137");
    hosts.add("192.168.233.138");
    hosts.add("192.168.233.139");
    hosts.add("192.168.233.140");
    hosts.add("192.168.233.141");
    hosts.add("192.168.233.142");
    hosts.add("192.168.233.143");
    hosts.add("192.168.233.145");
    hosts.add("192.168.233.146");
    hosts.add("192.168.233.147");
    hosts.add("192.168.233.148");
    hosts.add("192.168.233.149");
    hosts.add("192.168.233.151");
    hosts.add("192.168.233.152");
    hosts.add("192.168.233.153");
    hosts.add("192.168.233.154");
    hosts.add("192.168.233.155");
    hosts.add("192.168.233.156");
    hosts.add("192.168.233.157");
    hosts.add("192.168.233.158");
    hosts.add("192.168.233.159");
    hosts.add("192.168.233.160");
    hosts.add("192.168.233.161");
    hosts.add("192.168.233.162");
    hosts.add("192.168.233.163");
    hosts.add("192.168.233.164");
    hosts.add("192.168.233.165");
    hosts.add("192.168.233.166");
    hosts.add("192.168.233.167");
    hosts.add("192.168.233.168");
    hosts.add("192.168.233.169");
    hosts.add("192.168.233.170");
    hosts.add("192.168.233.171");
    hosts.add("192.168.233.172");
    hosts.add("192.168.233.173");
    hosts.add("192.168.233.174");
    hosts.add("192.168.233.175");
    hosts.add("192.168.233.217");
    hosts.add("192.168.233.254");
    hosts.add("192.168.233.255");
    return hosts;
  }
}</string></string></string></string>

4. Conexión al Servidor Intermedio

5. Escaneo de Puertos

package red;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class EscaneadorPuertosFX extends Application {
  private TextField campoHostIP;    // Campo de entrada para IP del host objetivo
  private TextField campoPuertoInicio; // Campo de entrada para puerto inicial
  private TextField campoPuertoFin;   // Campo de entrada para puerto final
  private TextArea areaResultado;      // Área de resultados
  private ProgressBar barraProgreso;  // Barra de progreso
  private Label etiquetaProgreso;      // Etiqueta de porcentaje de progreso
  private Button btnEscaneo;           // Botón de escaneo normal
  private Button btnEscaneoRapido;       // Botón de escaneo rápido
  private Button btnEscaneoMultiHilo; // Botón de escaneo multihilo
  private Button btnDetener;           // Botón de detención

  private final AtomicInteger contadorPuertos = new AtomicInteger(0); // Puertos escaneados
  private final AtomicInteger totalPuertos = new AtomicInteger(0); // Total de puertos
  private final List<thread> hilosEscaneo = new ArrayList<>(); // Lista de hilos de escaneo
  private volatile boolean escaneando = false; // Estado de escaneo (volatile para visibilidad)
  private static final int NUMERO_HILOS_DEFECTO = 10; // Número de hilos por defecto

  @Override
  public void start(Stage primaryStage) {
    primaryStage.setTitle("Escaneador de Puertos");

    // 1. Diseño de la interfaz
    BorderPane root = new BorderPane();
    root.setPadding(new Insets(15));

    // Área de entrada (IP del host, puerto inicial, puerto final)
    VBox cajaEntrada = new VBox(10);
    cajaEntrada.setPadding(new Insets(10));
    cajaEntrada.setAlignment(Pos.CENTER);

    HBox cajaHostIP = new HBox(10);
    Label etiquetaHostIP = new Label("IP del host objetivo:");
    campoHostIP = new TextField("192.168.0.1");
    campoHostIP.setPrefWidth(150);
    cajaHostIP.getChildren().addAll(etiquetaHostIP, campoHostIP);

    HBox cajaRangoPuertos = new HBox(10);
    Label etiquetaPuertoInicio = new Label("Puerto inicial:");
    campoPuertoInicio = new TextField("1");
    campoPuertoInicio.setPrefWidth(80);
    Label etiquetaPuertoFin = new Label("Puerto final:");
    campoPuertoFin = new TextField("1000");
    campoPuertoFin.setPrefWidth(80);
    cajaRangoPuertos.getChildren().addAll(etiquetaPuertoInicio, campoPuertoInicio, etiquetaPuertoFin, campoPuertoFin);

    cajaEntrada.getChildren().addAll(cajaHostIP, cajaRangoPuertos);

    // Área de botones
    HBox cajaBotones = new HBox(10);
    cajaBotones.setPadding(new Insets(10));
    cajaBotones.setAlignment(Pos.CENTER);

    btnEscaneo = new Button("Escaneo");
    btnEscaneo.setPrefWidth(80);
    btnEscaneoRapido = new Button("Escaneo Rápido");
    btnEscaneoRapido.setPrefWidth(80);
    btnEscaneoMultiHilo = new Button("Escaneo Multihilo");
    btnEscaneoMultiHilo.setPrefWidth(100);
    btnDetener = new Button("Detener Escaneo");
    btnDetener.setPrefWidth(80);
    btnDetener.setDisable(true);

    cajaBotones.getChildren().addAll(btnEscaneo, btnEscaneoRapido, btnEscaneoMultiHilo, btnDetener);

    // Área de barra de progreso
    HBox cajaProgreso = new HBox(10);
    cajaProgreso.setPadding(new Insets(10, 0, 0, 0));
    cajaProgreso.setAlignment(Pos.CENTER);

    etiquetaProgreso = new Label("0%");
    barraProgreso = new ProgressBar(0);
    barraProgreso.setPrefWidth(300);
    barraProgreso.setMaxWidth(Double.MAX_VALUE);
    HBox.setHgrow(barraProgreso, Priority.ALWAYS);

    cajaProgreso.getChildren().addAll(etiquetaProgreso, barraProgreso);

    // Área de resultados
    areaResultado = new TextArea();
    areaResultado.setEditable(false);
    areaResultado.setWrapText(true);

    // Ensamblaje de la interfaz
    VBox cajaSuperior = new VBox(15);
    cajaSuperior.getChildren().addAll(cajaEntrada, cajaBotones, cajaProgreso);
    root.setTop(cajaSuperior);
    root.setCenter(areaResultado);

    // 2. Asignación de eventos
    btnEscaneo.setOnAction(e -> iniciarEscaneoPuertos(false, false));
    btnEscaneoRapido.setOnAction(e -> iniciarEscaneoPuertos(true, false));
    btnEscaneoMultiHilo.setOnAction(e -> iniciarEscaneoPuertos(true, true));
    btnDetener.setOnAction(e -> detenerEscaneoPuertos());

    // 3. Configuración del escenario
    Scene scene = new Scene(root, 600, 450);
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  /**
   * Iniciar escaneo de puertos
   * @param esRapido ¿Es escaneo rápido (con timeout)?
   * @param esMultiHilo ¿Es escaneo multihilo?
   */
  private void iniciarEscaneoPuertos(boolean esRapido, boolean esMultiHilo) {
    // Detener escaneo anterior
    detenerEscaneoPuertos();

    String host = campoHostIP.getText().trim();
    String strPuertoInicio = campoPuertoInicio.getText().trim();
    String strPuertoFin = campoPuertoFin.getText().trim();

    // Validar entrada
    if (!esIPValida(host)) {
      areaResultado.appendText("Error: ¡Formato de IP del host objetivo inválido!\n");
      return;
    }

    int puertoInicio, puertoFin;
    try {
      puertoInicio = Integer.parseInt(strPuertoInicio);
      puertoFin = Integer.parseInt(strPuertoFin);
      if (puertoInicio < 1 || puertoFin > 65535 || puertoInicio > puertoFin) {
        areaResultado.appendText("Error: ¡Rango de puertos inválido (1-65535)!\n");
        return;
      }
    } catch (NumberFormatException e) {
      areaResultado.appendText("Error: ¡Los números de puerto deben ser enteros!\n");
      return;
    }

    // Inicializar estado de escaneo
    escaneando = true;
    contadorPuertos.set(0);
    totalPuertos.set(puertoFin - puertoInicio + 1);
    barraProgreso.setProgress(0);
    etiquetaProgreso.setText("0%");
    btnEscaneo.setDisable(true);
    btnEscaneoRapido.setDisable(true);
    btnEscaneoMultiHilo.setDisable(true);
    btnDetener.setDisable(false);
    areaResultado.clear();
    areaResultado.appendText("Iniciando escaneo de " + host + " en rango de puertos: " + puertoInicio + " - " + puertoFin + "\n");
    areaResultado.appendText("Modo de escaneo: " + (esMultiHilo ? "Multihilo" : "Unihilo") + " + " + (esRapido ? "Rápido" : "Normal") + "\n");
    areaResultado.appendText("==============================\n");

    if (esMultiHilo) {
      // Escaneo multihilo
      CountDownLatch latch = new CountDownLatch(NUMERO_HILOS_DEFECTO);
      for (int i = 0; i < NUMERO_HILOS_DEFECTO; i++) {
        int numHilo = i;
        Thread hilo = new Thread(() -> {
          try {
            escanearRangoPuertos(host, puertoInicio, puertoFin, numHilo, NUMERO_HILOS_DEFECTO, esRapido);
          } finally {
            latch.countDown();
          }
        });
        hilosEscaneo.add(hilo);
        hilo.start();
      }

      // Esperar a que todos los hilos terminen y actualizar estado
      new Thread(() -> {
        try {
          latch.await();
          javafx.application.Platform.runLater(this::escaneoCompleto);
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt();
        }
      }).start();
    } else {
      // Escaneo unihilo
      Thread hiloEscaneo = new Thread(() -> {
        escanearRangoPuertos(host, puertoInicio, puertoFin, 0, 1, esRapido);
        javafx.application.Platform.runLater(this::escaneoCompleto);
      });
      hilosEscaneo.add(hiloEscaneo);
      hiloEscaneo.start();
    }
  }

  /**
   * Escanear rango de puertos (tarea del hilo)
   * @param host Host objetivo
   * @param puertoInicio Puerto inicial
   * @param puertoFin Puerto final
   * @param numHilo Número de hilo
   * @param totalHilos Total de hilos
   * @param esRapido ¿Es escaneo rápido?
   */
  private void escanearRangoPuertos(String host, int puertoInicio, int puertoFin, int numHilo, int totalHilos, boolean esRapido) {
    for (int puerto = puertoInicio + numHilo; puerto <= puertoFin && escaneando; puerto += totalHilos) {
      try (Socket socket = new Socket()) { // try-with-resources para cierre automático
        if (esRapido) {
          socket.connect(new InetSocketAddress(host, puerto), 300); // Timeout de 300ms para escaneo rápido
        } else {
          socket.connect(new InetSocketAddress(host, puerto)); // Escaneo normal (timeout por defecto)
        }
        // Puerto abierto
        String resultado = host + " puerto " + puerto + " está abierto\n";
        javafx.application.Platform.runLater(() -> areaResultado.appendText(resultado));
      } catch (Exception e) {
        // Puerto cerrado o excepción, no mostrar
      }
      // Actualizar progreso
      actualizarProgreso();
    }
  }

  /**
   * Actualizar progreso de escaneo
   */
  private void actualizarProgreso() {
    int count = contadorPuertos.incrementAndGet();
    double progreso = (double) count / totalPuertos.get();
    DecimalFormat df = new DecimalFormat("0%");
    javafx.application.Platform.runLater(() -> {
      barraProgreso.setProgress(progreso);
      etiquetaProgreso.setText(df.format(progreso));
    });
  }

  /**
   * Restablecer estado después de completar escaneo
   */
  private void escaneoCompleto() {
    areaResultado.appendText("==============================\n");
    areaResultado.appendText("¡Escaneo completado! Puertos escaneados: " + totalPuertos.get() + "\n");
    escaneando = false;
    btnEscaneo.setDisable(false);
    btnEscaneoRapido.setDisable(false);
    btnEscaneoMultiHilo.setDisable(false);
    btnDetener.setDisable(true);
    hilosEscaneo.clear();
  }

  /**
   * Detener escaneo de puertos
   */
  private void detenerEscaneoPuertos() {
    if (escaneando) {
      escaneando = false;
      // Interrumpir todos los hilos de escaneo
      for (Thread hilo : hilosEscaneo) {
        if (hilo.isAlive()) {
          hilo.interrupt();
        }
      }
      areaResultado.appendText("\n¡Escaneo detenido!\n");
      hilosEscaneo.clear();
    }
    btnEscaneo.setDisable(false);
    btnEscaneoRapido.setDisable(false);
    btnEscaneoMultiHilo.setDisable(false);
    btnDetener.setDisable(true);
  }

  /**
   * Validación de formato de IP
   */
  private boolean esIPValida(String ip) {
    String regex = "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$";
    return ip.matches(regex);
  }

  public static void main(String[] args) {
    launch(args);
  }
}</thread>

Etiquetas: JavaFX java Escaneo de Redes programación de redes TCP/IP

Publicado el 6-15 02:10