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

85 lines
2.5 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,
ip4Address.Port,
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);
}
}