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>