ajustes contra corrida

This commit is contained in:
Diego Freitas 2026-03-05 12:18:40 -03:00
parent c03c5b1736
commit e718a3858f
2 changed files with 63 additions and 25 deletions

View File

@ -21,6 +21,7 @@ using System.Diagnostics;
using Newtonsoft.Json; using Newtonsoft.Json;
using AgroMonitor; using AgroMonitor;
using System.Net; using System.Net;
using System.Net.Sockets;
namespace AgroBase.Models namespace AgroBase.Models
{ {
@ -328,9 +329,24 @@ namespace AgroBase.Models
double ms = (DateTime.UtcNow - lastPkt).TotalMilliseconds; double ms = (DateTime.UtcNow - lastPkt).TotalMilliseconds;
if (ms > UDP_RESTART_MS) if (ms > UDP_RESTART_MS)
{
try
{ {
await RestartUdpChannelSafe(); await RestartUdpChannelSafe();
} }
catch (SocketException)
{
// normal durante restart
}
catch (ObjectDisposedException)
{
// normal durante restart
}
catch (Exception ex)
{
Console.WriteLine("[UDP] Watchdog exception: " + ex.Message);
}
}
} }
finally finally
{ {

View File

@ -38,6 +38,8 @@ public sealed class UdpReliableChannel : IDisposable
private CancellationTokenSource _hbCts; private CancellationTokenSource _hbCts;
private Task _hbTask; private Task _hbTask;
private int _hbRunning = 0; private int _hbRunning = 0;
private readonly object _sockLock = new object();
private volatile bool _stopping = false;
public void SetRemote(string ip, int port) public void SetRemote(string ip, int port)
@ -71,37 +73,37 @@ public sealed class UdpReliableChannel : IDisposable
public void Stop() public void Stop()
{ {
lock (_sockLock)
{
_stopping = true;
_running = false; _running = false;
}
// pare heartbeat antes de matar socket
StopHeartbeat(); StopHeartbeat();
try { _udp?.Close(); } catch { } // força o Receive quebrar try { _udp?.Close(); } catch { }
try { _udp?.Dispose(); } catch { } // garante liberar socket try { _udp?.Dispose(); } catch { }
// espera thread encerrar (pra não ficar thread velha viva)
try try
{ {
if (_rxThread != null && _rxThread.IsAlive) if (_rxThread != null && _rxThread.IsAlive)
{ _rxThread.Join(500);
if (!_rxThread.Join(500))
{
// Se travar, não aborta (Thread.Abort é treta), só segue.
// Mas normalmente Close() já libera.
}
}
} }
catch { } catch { }
lock (_sockLock)
{
_udp = null; _udp = null;
_rxThread = null; _rxThread = null;
// reseta sequência RX pra evitar descartar tudo após restart
_lastSeqRx = 0; _lastSeqRx = 0;
// opcional: limpa ACKs pendentes pra não vazar
foreach (var kv in _pendingAck) foreach (var kv in _pendingAck)
kv.Value.TrySetResult(false); kv.Value.TrySetResult(false);
_pendingAck.Clear(); _pendingAck.Clear();
_stopping = false;
}
} }
public void Dispose() public void Dispose()
@ -214,8 +216,19 @@ public sealed class UdpReliableChannel : IDisposable
private Task SendInternalAsync(byte type, byte[] payload, uint seq, uint tsMs, bool requestAck) private Task SendInternalAsync(byte type, byte[] payload, uint seq, uint tsMs, bool requestAck)
{ {
if (_udp == null) throw new InvalidOperationException("Channel not started."); UdpClient udp;
if (Remote == null) throw new InvalidOperationException("Remote not set."); IPEndPoint remote;
lock (_sockLock)
{
if (_stopping || !_running) return Task.CompletedTask;
udp = _udp;
remote = Remote;
}
if (udp == null) return Task.CompletedTask;
if (remote == null) return Task.CompletedTask;
if (payload.Length > MaxPayloadBytes) if (payload.Length > MaxPayloadBytes)
throw new ArgumentException("Payload too big (" + payload.Length + " > " + MaxPayloadBytes + ")."); throw new ArgumentException("Payload too big (" + payload.Length + " > " + MaxPayloadBytes + ").");
@ -223,7 +236,6 @@ public sealed class UdpReliableChannel : IDisposable
byte flags = (byte)(requestAck ? 1 : 0); byte flags = (byte)(requestAck ? 1 : 0);
byte[] buf = new byte[12 + payload.Length]; byte[] buf = new byte[12 + payload.Length];
// magic BE
buf[0] = (byte)(MAGIC >> 8); buf[0] = (byte)(MAGIC >> 8);
buf[1] = (byte)(MAGIC & 0xFF); buf[1] = (byte)(MAGIC & 0xFF);
buf[2] = type; buf[2] = type;
@ -235,8 +247,18 @@ public sealed class UdpReliableChannel : IDisposable
if (payload.Length > 0) if (payload.Length > 0)
Buffer.BlockCopy(payload, 0, buf, 12, payload.Length); Buffer.BlockCopy(payload, 0, buf, 12, payload.Length);
// UdpClient.SendAsync existe no .NET Framework 4.6+, ok. try
return _udp.SendAsync(buf, buf.Length, Remote); {
return udp.SendAsync(buf, buf.Length, remote);
}
catch (ObjectDisposedException)
{
return Task.CompletedTask;
}
catch (SocketException)
{
return Task.CompletedTask;
}
} }
private void RxLoop() private void RxLoop()