2023-05-04 07:32:35 +00:00
|
|
|
using System.Net.Sockets;
|
|
|
|
using InnovEnergy.Lib.Protocols.Modbus.Protocol;
|
2023-07-03 15:29:12 +00:00
|
|
|
using InnovEnergy.Lib.Utils.Net;
|
2023-05-04 07:32:35 +00:00
|
|
|
|
|
|
|
namespace InnovEnergy.Lib.Protocols.Modbus.Channels;
|
|
|
|
|
|
|
|
public class TcpChannel : ConnectionChannel<TcpClient>
|
|
|
|
{
|
2023-07-10 08:38:46 +00:00
|
|
|
private const Int32 TimeoutMs = 500; // TODO: parametrize
|
2023-07-03 15:29:12 +00:00
|
|
|
|
2023-07-10 08:38:46 +00:00
|
|
|
public TcpChannel(Ip4Address ip4Address,
|
|
|
|
Boolean closeAfterSuccessfulRead = false,
|
|
|
|
Boolean closeAfterSuccessfulWrite = false) :
|
|
|
|
this(ip4Address.Host,
|
|
|
|
ip4Address.Port,
|
|
|
|
closeAfterSuccessfulRead,
|
|
|
|
closeAfterSuccessfulWrite)
|
2023-07-03 15:29:12 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
public TcpChannel(String hostname,
|
|
|
|
Int32 port,
|
|
|
|
Boolean closeAfterSuccessfulRead = false,
|
|
|
|
Boolean closeAfterSuccessfulWrite = false) : base(closeAfterSuccessfulRead, closeAfterSuccessfulWrite)
|
|
|
|
{
|
2023-07-10 08:38:46 +00:00
|
|
|
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}");
|
|
|
|
}
|
|
|
|
|
2023-05-04 07:32:35 +00:00
|
|
|
_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);
|
|
|
|
}
|
|
|
|
}
|