using System.Net.Sockets; using InnovEnergy.Lib.Protocols.Modbus.Protocol; using InnovEnergy.Lib.Utils.Net; /*namespace InnovEnergy.Lib.Protocols.Modbus.Channels; public class TcpChannel : ConnectionChannel { private const Int32 TimeoutMs = 500; // TODO: parametrize public TcpChannel(Ip4Address ip4Address, Boolean closeAfterSuccessfulRead = false, Boolean closeAfterSuccessfulWrite = false) : this(ip4Address.Host ?? "null", ip4Address.Port.HasValue ? (Int32)ip4Address.Port.Value : 0, closeAfterSuccessfulRead, closeAfterSuccessfulWrite) { } public TcpChannel(String hostname, Int32 port, Boolean closeAfterSuccessfulRead = false, Boolean closeAfterSuccessfulWrite = false) : base(closeAfterSuccessfulRead, closeAfterSuccessfulWrite) { TcpClient Open() { var tcpClient = new TcpClient { LingerState = new LingerOption(false, 0), NoDelay = true, ReceiveTimeout = TimeoutMs, SendTimeout = TimeoutMs }; var cts = new CancellationTokenSource(); var connected = tcpClient .ConnectAsync(hostname, port, cts.Token) .AsTask() .Wait(TimeoutMs); if (connected) return tcpClient; cts.Cancel(); throw new Exception($"Failed to connect to {hostname}:{port}"); } _Open = Open; } private readonly Func _Open; protected override TcpClient Open() => _Open(); protected override void Close(TcpClient tcpClient) => tcpClient.Close(); protected override IReadOnlyList Read(TcpClient tcpClient, Int32 nToRead) { var buffer = new Byte[nToRead]; var stream = tcpClient.GetStream(); var nReceived = 0; do { var nRemaining = nToRead - nReceived; var read = stream.Read(buffer, nReceived, nRemaining); if (read <= 0) throw new NotConnectedException("The TCP Connection was closed"); nReceived += read; } while (nReceived < nToRead); return buffer; } protected override void Write(TcpClient tcpClient, IReadOnlyList data) { var array = data.ToArray(); tcpClient.GetStream().Write(array, 0, array.Length); } }*/ using System; using System.Net.Sockets; namespace InnovEnergy.Lib.Protocols.Modbus.Channels { public class TcpChannel : Channel, IDisposable { public string Host { get; } public ushort Port { get; } private const int TimeoutMs = 500; // TODO: parametrize private Socket? Socket { get; set; } private byte[] Buffer { get; } public TcpChannel(string hostname, ushort port) { Host = hostname ?? throw new ArgumentNullException(nameof(hostname)); Port = port; Buffer = new byte[8192]; // Buffer size can be adjusted } public override IReadOnlyList Read(int nBytes) { if (Socket == null) throw new InvalidOperationException("Socket is not connected."); var buffer = new byte[nBytes]; int bytesRead = 0; while (bytesRead < nBytes) { var read = Socket.Receive(buffer, bytesRead, nBytes - bytesRead, SocketFlags.None); if (read == 0) throw new Exception("Socket closed."); bytesRead += read; } return buffer; } public override void Write(IReadOnlyList bytes) { if (Socket == null) throw new InvalidOperationException("Socket is not connected."); Socket.Send(bytes.ToArray(), SocketFlags.None); } public void Connect() { if (Socket != null) return; Socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { Blocking = true, NoDelay = true, LingerState = new LingerOption(false, 0), ReceiveTimeout = TimeoutMs, SendTimeout = TimeoutMs }; var cts = new CancellationTokenSource(); cts.CancelAfter(TimeoutMs); try { Socket.ConnectAsync(Host, Port).Wait(TimeoutMs); } catch { Socket = null; throw; } } public void Disconnect() { if (Socket == null) return; try { Socket.Close(); } finally { Socket = null; } } public void Dispose() { Disconnect(); } } }