186 lines
5.1 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|
|
|