Innovenergy_trunk/csharp/Lib/Protocols/Modbus/Channels/TcpChannel.cs

186 lines
5.1 KiB
C#

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<TcpClient>
{
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<TcpClient> _Open;
protected override TcpClient Open() => _Open();
protected override void Close(TcpClient tcpClient) => tcpClient.Close();
protected override IReadOnlyList<Byte> 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<Byte> 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<byte> 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<byte> 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();
}
}
}