using System.IO; using System.Net; using System.Net.Sockets; using System.Windows.Media.Imaging; namespace OperationControl.Models { public class TcpVideoReceiver { private readonly int _port; private readonly System.Windows.Controls.Image _imageControl; public readonly string imageName; private volatile bool _rodando; private Thread _thread; private TcpListener _listener; public TcpVideoReceiver(int port, System.Windows.Controls.Image imageControl) { _port = port; _imageControl = imageControl; imageName = imageControl.Name; } public void Iniciar() { if (_rodando) return; _rodando = true; _thread = new Thread(Run) { IsBackground = true }; _thread.Start(); } public void Parar() { _rodando = false; try { _listener?.Stop(); _imageControl.Source = null; } catch { /* ignora */ } } private void Run() { try { _listener = new TcpListener(IPAddress.Any, _port); _listener.Start(); Console.WriteLine($"[VideoReceiver] Ouvindo na porta {_port}..."); while (_rodando) { TcpClient client = null; try { // Em vez de bloquear direto no Accept, usamos Pending() + Sleep if (!_listener.Pending()) { Thread.Sleep(100); continue; } client = _listener.AcceptTcpClient(); client.NoDelay = true; Console.WriteLine("[VideoReceiver] Cliente conectado."); using (var stream = client.GetStream()) using (var br = new BinaryReader(stream)) { while (_rodando && client.Connected) { // 1) lê tamanho (4 bytes big-endian) byte[] sizeBytes = br.ReadBytes(4); if (sizeBytes.Length < 4) break; int size = (sizeBytes[0] << 24) | (sizeBytes[1] << 16) | (sizeBytes[2] << 8) | (sizeBytes[3]); // 2) lê JPEG byte[] imgBytes = br.ReadBytes(size); if (imgBytes.Length < size) break; _imageControl.Dispatcher.BeginInvoke(new Action(() => { try { using (var ms = new MemoryStream(imgBytes)) { var bmp = new BitmapImage(); bmp.BeginInit(); bmp.CacheOption = BitmapCacheOption.OnLoad; bmp.StreamSource = ms; bmp.EndInit(); bmp.Freeze(); _imageControl.Source = bmp; } } catch { // ignora frame corrompido ou problema de decode } })); } } Console.WriteLine("[VideoReceiver] Cliente desconectado."); client.Close(); } catch (SocketException ex) { // WSACancelBlockingCall ao parar o listener é normal if (!_rodando) break; Console.WriteLine("[VideoReceiver] SocketException: " + ex.Message); client?.Close(); Thread.Sleep(500); } catch (IOException) { // desconexão abrupta do cliente client?.Close(); Thread.Sleep(200); } catch (Exception ex) { Console.WriteLine("[VideoReceiver] Erro geral: " + ex.Message); client?.Close(); Thread.Sleep(500); } } Console.WriteLine("[VideoReceiver] Loop encerrado."); } catch (Exception ex) { Console.WriteLine("[VideoReceiver] Erro ao iniciar listener: " + ex.Message); } finally { try { _listener?.Stop(); } catch { } } } } }