Files
Scanbox/ScanBox/TcpReaderSearcher.cs
2026-02-09 15:37:45 -06:00

248 lines
8.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace ScaBox30.Controller
{
/// <summary>
/// Reemplazo del ReaderSearcher del SDK
/// Busca sensores SR-X300W en la red mediante escaneo TCP
/// </summary>
public class TcpReaderSearcher : IDisposable
{
private bool isSearching = false;
private List<NicSearchResult> nicList = new List<NicSearchResult>();
public bool IsSearching => isSearching;
public NicSearchResult SelectedNicSearchResult { get; set; }
/// <summary>
/// Lista las interfaces de red disponibles en el equipo
/// Compatible con: m_nicList = m_searcher.ListUpNic()
/// </summary>
public List<NicSearchResult> ListUpNic()
{
nicList.Clear();
try
{
foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
{
// Filtrar solo interfaces activas y Ethernet/Wi-Fi
if (ni.OperationalStatus == OperationalStatus.Up &&
(ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet ||
ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211))
{
IPInterfaceProperties ipProps = ni.GetIPProperties();
foreach (UnicastIPAddressInformation ip in ipProps.UnicastAddresses)
{
// Solo IPv4
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
{
var nicResult = new NicSearchResult
{
NicIpAddr = ip.Address.ToString(),
NicName = ni.Name,
NicDescription = ni.Description
};
nicList.Add(nicResult);
Console.WriteLine($"[NIC] Encontrada: {nicResult.NicIpAddr} ({nicResult.NicName})");
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"[NIC] Error listando interfaces: {ex.Message}");
}
return nicList;
}
/// <summary>
/// Inicia búsqueda de sensores en la red
/// Compatible con: m_searcher.Start((res) => { ... })
/// </summary>
public void Start(Action<SearchResult> onSensorFound)
{
if (isSearching)
{
Console.WriteLine("[SEARCH] Ya hay una búsqueda en curso");
return;
}
if (SelectedNicSearchResult == null)
{
Console.WriteLine("[SEARCH] ERROR: No se ha seleccionado una NIC");
return;
}
isSearching = true;
Console.WriteLine($"[SEARCH] Iniciando búsqueda desde {SelectedNicSearchResult.NicIpAddr}...");
// Ejecutar búsqueda en background
Task.Run(() => SearchSensorsInNetwork(onSensorFound));
}
/// <summary>
/// Busca sensores SR-X300W en la red local
/// Prueba conectar al puerto 9004 (puerto de comandos SR-X300W)
/// </summary>
private async void SearchSensorsInNetwork(Action<SearchResult> onSensorFound)
{
try
{
string localIP = SelectedNicSearchResult.NicIpAddr;
string subnet = GetSubnet(localIP);
int port = 9004; // Puerto TCP comandos SR-X300W
Console.WriteLine($"[SEARCH] Escaneando subnet {subnet}.x en puerto {port}");
// Escanear rango de IPs (ejemplo: 192.168.100.1 - 192.168.100.254)
List<Task> scanTasks = new List<Task>();
for (int i = 1; i <= 254; i++)
{
string testIP = $"{subnet}.{i}";
// No probar la IP local
if (testIP == localIP)
continue;
// Lanzar escaneo asíncrono
scanTasks.Add(Task.Run(async () =>
{
if (await TryConnectToSensor(testIP, port, 500)) // 500ms timeout
{
Console.WriteLine($"[SEARCH] ✓ Sensor encontrado en {testIP}:{port}");
var result = new SearchResult
{
IpAddress = testIP,
Port = port,
IsResponding = true
};
onSensorFound?.Invoke(result);
}
}));
// Limitar concurrencia para no saturar la red
if (scanTasks.Count >= 20)
{
await Task.WhenAll(scanTasks);
scanTasks.Clear();
}
}
// Esperar tareas restantes
await Task.WhenAll(scanTasks);
Console.WriteLine("[SEARCH] Búsqueda completada");
}
catch (Exception ex)
{
Console.WriteLine($"[SEARCH] Error en búsqueda: {ex.Message}");
}
finally
{
isSearching = false;
}
}
/// <summary>
/// Intenta conectar a una IP:Puerto con timeout
/// </summary>
private async Task<bool> TryConnectToSensor(string ip, int port, int timeoutMs)
{
try
{
using (var client = new TcpClient())
{
var connectTask = client.ConnectAsync(ip, port);
var timeoutTask = Task.Delay(timeoutMs);
if (await Task.WhenAny(connectTask, timeoutTask) == connectTask)
{
// Conexión exitosa
if (client.Connected)
{
// Verificar que responda a un comando básico
using (var stream = client.GetStream())
{
stream.ReadTimeout = 500;
byte[] testCmd = System.Text.Encoding.ASCII.GetBytes("NUM\r");
await stream.WriteAsync(testCmd, 0, testCmd.Length);
byte[] buffer = new byte[256];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
return bytesRead > 0; // Si responde, es un sensor válido
}
}
}
}
}
catch
{
// Silenciosamente ignorar fallos (IP no responde)
}
return false;
}
/// <summary>
/// Obtiene la subred de una IP (ejemplo: 192.168.100.1 -> 192.168.100)
/// </summary>
private string GetSubnet(string ip)
{
string[] parts = ip.Split('.');
if (parts.Length == 4)
{
return $"{parts[0]}.{parts[1]}.{parts[2]}";
}
return "192.168.100"; // Fallback
}
/// <summary>
/// Detiene la búsqueda
/// </summary>
public void Stop()
{
isSearching = false;
Console.WriteLine("[SEARCH] Búsqueda detenida");
}
public void Dispose()
{
Stop();
}
}
/// <summary>
/// Resultado de búsqueda de NIC (compatible con SDK)
/// </summary>
public class NicSearchResult
{
public string NicIpAddr { get; set; }
public string NicName { get; set; }
public string NicDescription { get; set; }
}
/// <summary>
/// Resultado de búsqueda de sensor
/// </summary>
public class SearchResult
{
public string IpAddress { get; set; }
public int Port { get; set; }
public bool IsResponding { get; set; }
}
}