Innovenergy_trunk/csharp/Lib/Channels/V2/TcpChannel.cs

114 lines
2.5 KiB
C#

using System.Net.Sockets;
namespace InnovEnergy.Lib.Channels.V2;
public class TcpChannel : IChannel<IReadOnlyList<Byte>>
{
private Int32 TimeoutMs { get; }
private String Hostname { get; }
private UInt16 Port { get; }
private Byte[] Buffer { get; }
private Socket? Socket { get; set; }
public TcpChannel(String hostname,
UInt16 port,
TimeSpan timeout = default,
Int32 bufferSize = 8192)
{
if (bufferSize <= 0)
throw new ArgumentOutOfRangeException(nameof(bufferSize));
Hostname = hostname;
Port = port;
TimeoutMs = (Int32)timeout.TotalMilliseconds;
Buffer = new Byte[bufferSize];
}
public async Task<IReadOnlyList<Byte>> Read()
{
try
{
await Open();
var nRead = await Socket!.ReceiveAsync(Buffer, SocketFlags.None);
if (nRead <= 0)
throw new Exception("TCP Connection was closed");
// copy from buffer, so we can reuse it
var data = new Byte[nRead];
Array.Copy(Buffer, data, nRead);
return data;
}
catch
{
Close();
throw;
}
}
private async Task Open()
{
if (Socket is not null)
return;
Socket = new Socket(SocketType.Stream, ProtocolType.Tcp)
{
Blocking = true,
NoDelay = true,
LingerState = new LingerOption(false, 0),
ReceiveBufferSize = Buffer.Length,
SendBufferSize = Buffer.Length,
ReceiveTimeout = TimeoutMs,
SendTimeout = TimeoutMs,
};
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeoutMs);
try
{
await Socket.ConnectAsync(Hostname, Port, cts.Token).AsTask();
}
catch
{
Socket = null!;
throw;
}
}
public async Task Write(IReadOnlyList<Byte> tx)
{
try
{
await Open();
await Socket!.SendAsync(tx as Byte[] ?? tx.ToArray(), SocketFlags.None);
}
catch
{
Close();
throw;
}
}
private void Close()
{
if (Socket is null)
return;
try
{
Socket.Dispose();
}
finally
{
Socket = null;
}
}
}