agrobot_base/AgroBase/AgroBase/Services/EthernetService.cs

608 lines
20 KiB
C#

using AgroBase.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
public class EthernetService
{
public readonly string _ipAddress;
private readonly int _port;
private TcpClient _client;
private NetworkStream _networkStream;
public bool IsConnected
{
get
{
try
{
// Verifica se o cliente foi inicializado e está conectado
return _client != null && _client.Client != null && _client.Client.Connected;
}
catch
{
return false;
}
}
}
public EthernetService(string ipAddress, int port)
{
_ipAddress = ipAddress;
_port = port;
}
// Método para estabelecer conexão TCP com o conversor Ethernet-RS485
public async Task<bool> ConnectAsync(int timeoutMilliseconds = 1000)
{
try
{
_client = new TcpClient();
using (var cts = new CancellationTokenSource(timeoutMilliseconds))
{
var connectTaskCompletionSource = new TaskCompletionSource<bool>();
var connectTask = _client.ConnectAsync(_ipAddress, _port).ContinueWith(t =>
{
if (t.IsCompleted)
{
connectTaskCompletionSource.TrySetResult(true);
}
else if (t.IsFaulted)
{
connectTaskCompletionSource.TrySetException(t.Exception?.InnerException ?? t.Exception);
}
else
{
connectTaskCompletionSource.TrySetResult(false);
}
}, TaskScheduler.Default);
var completedTask = await Task.WhenAny(connectTaskCompletionSource.Task, Task.Delay(timeoutMilliseconds, cts.Token));
if (completedTask == connectTaskCompletionSource.Task && await connectTaskCompletionSource.Task)
{
if (_client.Connected)
{
_networkStream = _client.GetStream();
return true;
}
}
// Timeout foi atingido; limpa a conexão
Console.WriteLine("Conexão cancelada devido ao timeout.");
_client.Dispose();
return false;
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Conexão cancelada pela operação.");
return false;
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao conectar: {ex.Message}");
_client?.Close();
return false;
}
}
// Método para desconectar e liberar recursos
public void Disconnect()
{
try
{
_networkStream?.Close();
_client?.Close();
_networkStream = null;
_client = null;
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao desconectar: {ex.Message}");
}
}
// Método para enviar dados ao dispositivo via Ethernet
public async Task<bool> SendDataAsync(byte[] data)
{
if (IsConnected && (_networkStream?.CanWrite ?? false))
{
try
{
await FlushBufferAsync(); // Limpa o buffer antes de enviar
await _networkStream?.WriteAsync(data, 0, data.Length);
await _networkStream?.FlushAsync();
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao enviar dados: {ex.Message}");
}
}
else
{
Console.WriteLine("Não conectado ao dispositivo.");
}
return false;
}
// Método para receber dados do dispositivo via Ethernet
public async Task<byte[]> ReceiveDataAsync(int expectedLength, int timeoutMilliseconds = 200)
{
var buffer = new byte[expectedLength];
try
{
var readTask = _networkStream?.ReadAsync(buffer, 0, expectedLength); // Tarefa de leitura sem o token
// Cria uma tarefa de delay que representa o timeout
if (await Task.WhenAny(readTask, Task.Delay(timeoutMilliseconds)) == readTask)
{
// Se readTask completa antes do timeout
var bytesRead = await readTask;
Array.Resize(ref buffer, bytesRead); // Ajusta o tamanho do buffer para os bytes lidos
return buffer;
}
else
{
// Se o timeout for atingido, retorna nulo ou exibe uma mensagem
Console.WriteLine("Timeout ao receber dados via Ethernet.");
await ReconnectAsync();
return null;
}
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao receber dados: {ex.Message}");
await ReconnectAsync();
return null;
}
finally
{
await _networkStream?.FlushAsync();
await FlushBufferAsync();
}
}
public async Task<byte[]> ReceiveDataAsync2(int bufferSize = 1024, int timeoutMilliseconds = 1000)
{
if (_networkStream == null || !_networkStream.CanRead)
{
Console.WriteLine("O NetworkStream não está disponível para leitura.");
return null;
}
Console.WriteLine("Iniciando teste de leitura do stream...");
try
{
var buffer = new byte[bufferSize];
var cancellationTokenSource = new CancellationTokenSource(timeoutMilliseconds);
while (!cancellationTokenSource.Token.IsCancellationRequested)
{
if (_networkStream.DataAvailable)
{
int bytesRead = await _networkStream.ReadAsync(buffer, 0, buffer.Length, cancellationTokenSource.Token);
if (bytesRead > 0)
{
// Exibe os dados lidos no console
Console.WriteLine($"Dados recebidos ({bytesRead} bytes): {BitConverter.ToString(buffer, 0, bytesRead)}");
return buffer;
}
else
{
Console.WriteLine("Nenhum dado foi lido.");
break;
}
}
else
{
await Task.Delay(10); // Aguarda brevemente antes de verificar novamente
}
}
Console.WriteLine("Leitura do stream finalizada ou timeout atingido.");
}
catch (OperationCanceledException)
{
Console.WriteLine("Timeout atingido durante o teste de leitura do stream.");
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao ler do stream: {ex.Message}");
}
return null;
}
public async Task<byte[]> ReceiveExactDataAsync(int expectedLength = 8, int timeoutMilliseconds = 1000)
{
if (_networkStream == null || !_networkStream.CanRead)
{
Console.WriteLine("O NetworkStream não está disponível para leitura.");
return null;
}
var buffer = new byte[expectedLength];
var bytesRead = 0;
var timeoutTask = Task.Delay(timeoutMilliseconds);
try
{
while (bytesRead < expectedLength)
{
var readTask = _networkStream.ReadAsync(buffer, bytesRead, expectedLength - bytesRead);
if (await Task.WhenAny(readTask, timeoutTask) == timeoutTask)
{
Console.WriteLine("Timeout ao esperar os dados.");
return null;
}
var readBytes = await readTask;
if (readBytes == 0)
{
Console.WriteLine("A conexão foi encerrada pelo dispositivo.");
return null;
}
bytesRead += readBytes;
}
Console.WriteLine($"Dados recebidos ({bytesRead} bytes): {BitConverter.ToString(buffer)}");
return buffer;
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao receber dados: {ex.Message}");
return null;
}
}
public async Task FlushBufferAsync(bool forcar = false)
{
try
{
var tempBuffer = new byte[1024]; // Buffer temporário para leitura
if (forcar)
{
await _networkStream?.ReadAsync(tempBuffer, 0, tempBuffer.Length);
}
else
{
if (_networkStream?.DataAvailable ?? false) // Verifica se há dados pendentes no buffer
{
while (_networkStream?.DataAvailable ?? false)
{
await _networkStream?.ReadAsync(tempBuffer, 0, tempBuffer.Length);
}
//Console.WriteLine("Buffer limpo.");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao limpar buffer: {ex.Message}");
}
}
// Método para verificar a conexão (pode ser usado para um "heartbeat")
public async Task<bool> CheckConnectionAsync()
{
if (!IsConnected)
{
Console.WriteLine("Conexão perdida. Tentando reconectar...");
return await ConnectAsync();
}
return true;
}
public bool _isReconnecting = false;
private int _reconnectAttempts = 0;
private const int MaxReconnectAttempts = 5;
private const int ReconnectInterval = 2000; // Intervalo de 2000 ms = 2 segundos
// Método para gerenciar a reconexão
public async Task<bool> ReconnectAsync()
{
if (_isReconnecting) return false; // Evita tentativas duplicadas
_isReconnecting = true;
try
{
while (_reconnectAttempts < MaxReconnectAttempts && !IsConnected)
{
Console.WriteLine($"Tentando reconectar ao IP {_ipAddress}... Tentativa {_reconnectAttempts + 1}");
bool connected = await ConnectAsync(5000);
if (connected)
{
Console.WriteLine("Reconexão bem-sucedida.");
_reconnectAttempts = 0;
return true;
}
else
{
_reconnectAttempts++;
await Task.Delay(ReconnectInterval);
}
}
if (!IsConnected)
{
Console.WriteLine("Número máximo de tentativas de reconexão atingido.");
await Task.Delay(5000);
_reconnectAttempts = 0;
}
return IsConnected;
}
finally
{
_isReconnecting = false; // Libera para novas tentativas futuras
}
}
public static List<string> ObterNomesInterfaces()
{
var listaInterfaces = new List<string>();
var interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var nic in interfaces)
{
string status = nic.OperationalStatus == OperationalStatus.Up ? "Ativa" : "Inativa";
listaInterfaces.Add($"{nic.Name} ({status})");
}
return listaInterfaces;
}
// Obtém o IP do gateway padrão (roteador) da rede ativa
public static string ObterIpGateway(string _interface)
{
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces().Where(x => x.Name == _interface))
{
if (networkInterface.OperationalStatus == OperationalStatus.Up)
{
foreach (GatewayIPAddressInformation gateway in networkInterface.GetIPProperties().GatewayAddresses)
{
if (gateway.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
return gateway.Address.ToString();
}
}
}
}
return null;
}
// Obtém o IP atual do PC na rede ativa
public static string ObterIpAtual(string _interface)
{
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces().Where(x => x.Name == _interface))
{
if (networkInterface.OperationalStatus == OperationalStatus.Up)
{
foreach (UnicastIPAddressInformation ip in networkInterface.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
return ip.Address.ToString();
}
}
}
}
return null;
}
public static string ObterSubnetMaskAtual(string _interface)
{
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces().Where(x => x.Name == _interface))
{
if (networkInterface.OperationalStatus == OperationalStatus.Up)
{
foreach (UnicastIPAddressInformation ip in networkInterface.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
return ip.IPv4Mask.ToString(); // Retorna a máscara de sub-rede como string
}
}
}
}
return null; // Retorna null se não encontrar uma máscara de sub-rede
}
public static string ObterTipoConfiguracaoIP(string _interface)
{
foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces().Where(x => x.Name == _interface))
{
if (networkInterface.OperationalStatus == OperationalStatus.Up)
{
var ipProperties = networkInterface.GetIPProperties();
if (ipProperties.GatewayAddresses.Count > 0) // Confirma que há um gateway configurado
{
// Verifica se o DHCP está habilitado para IPv4
if (ipProperties.GetIPv4Properties().IsDhcpEnabled)
{
return "Dinâmico (DHCP)";
}
else
{
return "IP Fixo (Estático)";
}
}
}
}
return "Nenhuma interface de rede ativa encontrada";
}
public static async Task<bool> DefinirIpDinamico(string interfaceName, bool response)
{
try
{
// Define o IP para DHCP
string comandoIp = $"interface ip set address \"{interfaceName}\" dhcp";
// Define o DNS para DHCP
string comandoDns = $"interface ip set dns \"{interfaceName}\" dhcp";
await ExecutarComandoNetshAsync(comandoIp);
await ExecutarComandoNetshAsync(comandoDns);
if (response)
{
MessageBox.Show("IP dinamico definido com sucesso!", "Configuração de IP", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
return true;
}
catch (Exception ex)
{
if (response)
{
MessageBox.Show($"Erro ao definir IP dinamico: {ex.Message}", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return false;
}
}
public static async Task<bool> DefinirIpFixo(string nomeInterface, string ipAddress, string subnetMask, string gateway, bool response)
{
try
{
// Define o IP fixo na interface de rede
string comandoIp = $"interface ip set address name=\"{nomeInterface}\" static {ipAddress} {subnetMask} {gateway}";
await ExecutarComandoNetshAsync(comandoIp);
// Configura o DNS para automático (caso desejado)
string comandoDns = $"interface ip set dns name=\"{nomeInterface}\" source=static addr=8.8.4.4 register=primary";
await ExecutarComandoNetshAsync(comandoDns);
if (response)
{
MessageBox.Show("IP fixo definido com sucesso!", "Configuração de IP", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
return true;
}
catch (Exception ex)
{
if (response)
{
MessageBox.Show($"Erro ao definir IP fixo: {ex.Message}", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return false;
}
}
private static string ExecutarComandoNetsh(string comando)
{
Process process = new Process();
process.StartInfo.FileName = "netsh";
process.StartInfo.Arguments = comando;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return output;
}
private static async Task<string> ExecutarComandoNetshAsync(string comando)
{
using (Process process = new Process())
{
process.StartInfo.FileName = "netsh";
process.StartInfo.Arguments = comando;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.Start();
string output = await process.StandardOutput.ReadToEndAsync();
await Task.Run(() => process.WaitForExit());
return output;
}
}
public static async Task ScanSubnetAsync(string subnet)
{
for (int i = 1; i <= 254; i++)
{
string ip = $"{subnet}.{i}";
bool isAlive = await PingAsync(ip);
if (isAlive)
{
Console.WriteLine($"Dispositivo ativo encontrado: {ip}");
}
}
}
public static async Task<bool> PingAsync(string ip)
{
try
{
using (Ping ping = new Ping())
{
PingReply reply = await ping.SendPingAsync(ip, 500); // 500 ms timeout
return reply.Status == IPStatus.Success;
}
}
catch
{
return false;
}
}
public static async Task<bool> ConfigurarIP(bool fixo, bool response)
{
bool sucesso = false;
var interfaces = ObterNomesInterfaces();
string _Interface = interfaces.FirstOrDefault(x => x.ToLower().Contains("wi-fi") && x.ToLower().Contains("ativa"));
if (!string.IsNullOrEmpty(_Interface))
{
_Interface = _Interface.Split('(')[0].Trim();
string gateway = ObterIpGateway(_Interface);
string ipAtual = ObterIpAtual(_Interface);
string ip = Variaveis.IP_Host;
string submask = ObterSubnetMaskAtual(_Interface);
if (fixo)
{
sucesso = await DefinirIpFixo(_Interface, ip, submask, gateway, response);
}
else
{
sucesso = await DefinirIpDinamico(_Interface, response);
}
}
return sucesso;
}
}