namespace Universal.IO; internal class IOTcpClient : BaseFilter, ITcpClient { #region Internal Variables public string? Name { get; internal set; } bool _bInitialize = false; volatile bool _bOpen = false; System.Net.Sockets.TcpClient? _tcpClient = null; Task? _readTask = null; TcpConnection? _tcpConnection = null; #endregion bool ITcpClient.Initiallize(string name) { lock (this) { if (_bInitialize) return false; this._bInitialize = true; this.Name = name; return true; } } bool ITcpClient.Open(string remoteHost, ushort remotePort, out TcpConnection? tcpConnection, string? localHost, ushort localPort, bool noDelay, int timeout, int receiveBufferSize) { tcpConnection = null; lock (this) { if (!_bInitialize) return false; if (_bOpen) return false; if (!IPAddress.TryParse(remoteHost, out IPAddress? remoteIPAddress) || remoteIPAddress is null) return false; AutoResetEvent? allowOpenEvent = new(false); bool result = false; try { _tcpClient = new() { NoDelay = noDelay }; if (string.IsNullOrEmpty(localHost) || !IPAddress.TryParse(localHost, out IPAddress? localIP) || localIP is null) { _tcpClient = new() { NoDelay = noDelay }; } else { IPEndPoint localEP = new(localIP, localPort); _tcpClient = new(localEP) { NoDelay = noDelay }; } using CancellationTokenSource cancellationTokenSource = new(); Task valueTask = _tcpClient.ConnectAsync(remoteIPAddress, remotePort); if (!valueTask.Wait(timeout)) { cancellationTokenSource.Cancel(); return false; } TcpConnection? connection = default; _readTask = Task.Factory.StartNew(async () => { try { if (_tcpClient.Client.LocalEndPoint is not IPEndPoint || _tcpClient.Client.RemoteEndPoint is not IPEndPoint) return; connection = new((IPEndPoint)_tcpClient.Client.LocalEndPoint, (IPEndPoint)_tcpClient.Client.RemoteEndPoint, null!); _tcpConnection = connection; NetworkStream networkStream = _tcpClient.GetStream(); Thread.Sleep(0); try { _bOpen = true; base.PrevConnector?.Connected(connection); result = true; } finally { allowOpenEvent.Set(); } for (byte[] buffer = new byte[receiveBufferSize]; ;) { int bytesRead = 0; DateTime receiveTime; try { bytesRead = await networkStream.ReadAsync(buffer); receiveTime = DateTime.Now; } catch { break; } if (bytesRead <= 0) break; byte[] cache = new byte[bytesRead]; Array.Copy(buffer, cache, bytesRead); Data receivedData = new(cache, connection, receiveTime); try { base.PrevReceiver?.Receive(receivedData); } catch { } } try { _tcpClient?.Close(); } catch { } try { base.PrevConnector?.Disconnected(connection); } catch { } _tcpClient = null; _bOpen = false; } catch { } }, TaskCreationOptions.LongRunning); } catch { _tcpClient = null; return false; } allowOpenEvent.WaitOne(); tcpConnection = _tcpConnection; if (result) return true; _tcpClient = null; return false; } } bool ITcpClient.Close() { lock (this) { if (!_bInitialize) return false; if (!_bOpen) return true; try { _tcpClient?.Close(); } catch { } _readTask?.Wait(); _readTask = null; _bOpen = false; return true; } } public override bool Send(Data data) { if (!_bInitialize) return false; if (!_bOpen) return false; if (_tcpClient?.Connected != true) return false; if (data.RawData is null || data.RawData.Length == 0) return false; try { NetworkStream networkStream = _tcpClient!.GetStream(); networkStream.Write([.. data.RawData], 0, data.RawData.Length); networkStream.Flush(); data.DateTime = DateTime.Now; } catch { return false; } return true; } void IDisposable.Dispose() { (this as ITcpClient).Close(); } }