Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions S7.Net.UnitTest/ConnectionCloseTest.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using S7.Net.Tcp;

namespace S7.Net.UnitTest
{
Expand Down Expand Up @@ -92,7 +91,7 @@ public async Task Test_CancellationDuringTransmission()
}

// Set a value to tcpClient field so we can later ensure that it has been closed.
tcpClientField.SetValue(plc, new TcpClient());
tcpClientField.SetValue(plc, new TcpClientWrapper());
var tcpClientValue = tcpClientField.GetValue(plc);
Assert.IsNotNull(tcpClientValue);

Expand Down Expand Up @@ -147,7 +146,7 @@ public async Task Test_CancellationBeforeTransmission()
}

// Set a value to tcpClient field so we can later ensure that it has been closed.
tcpClientField.SetValue(plc, new TcpClient());
tcpClientField.SetValue(plc, new TcpClientWrapper());
var tcpClientValue = tcpClientField.GetValue(plc);
Assert.IsNotNull(tcpClientValue);

Expand Down
24 changes: 17 additions & 7 deletions S7.Net/PLC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Net.Sockets;
using S7.Net.Internal;
using S7.Net.Protocol;
using S7.Net.Tcp;
using S7.Net.Types;


Expand All @@ -27,8 +28,11 @@ public partial class Plc : IDisposable

private readonly TaskQueue queue = new TaskQueue();

private readonly ITcpClientFactory _tcpClientFactory;

//TCP connection to device
private TcpClient? tcpClient;
private ITcpClient? tcpClient;

private NetworkStream? _stream;

private int readTimeout = DefaultTimeout; // default no timeout
Expand Down Expand Up @@ -124,8 +128,9 @@ public int WriteTimeout
/// <param name="rack">rack of the PLC, usually it's 0, but check in the hardware configuration of Step7 or TIA portal</param>
/// <param name="slot">slot of the CPU of the PLC, usually it's 2 for S7300-S7400, 0 for S7-1200 and S7-1500.
/// If you use an external ethernet card, this must be set accordingly.</param>
public Plc(CpuType cpu, string ip, Int16 rack, Int16 slot)
: this(cpu, ip, DefaultPort, rack, slot)
/// <param name="tcpClientFactory">Factory to provide the underlying <see cref="ITcpClient"/> for network communication.</param>
public Plc(CpuType cpu, string ip, Int16 rack, Int16 slot, ITcpClientFactory? tcpClientFactory = null)
: this(cpu, ip, DefaultPort, rack, slot, tcpClientFactory)
{
}

Expand All @@ -141,8 +146,9 @@ public Plc(CpuType cpu, string ip, Int16 rack, Int16 slot)
/// <param name="rack">rack of the PLC, usually it's 0, but check in the hardware configuration of Step7 or TIA portal</param>
/// <param name="slot">slot of the CPU of the PLC, usually it's 2 for S7300-S7400, 0 for S7-1200 and S7-1500.
/// If you use an external ethernet card, this must be set accordingly.</param>
public Plc(CpuType cpu, string ip, int port, Int16 rack, Int16 slot)
: this(ip, port, TsapPair.GetDefaultTsapPair(cpu, rack, slot))
/// <param name="tcpClientFactory">Factory to provide the underlying <see cref="ITcpClient"/> for network communication.</param>
public Plc(CpuType cpu, string ip, int port, Int16 rack, Int16 slot, ITcpClientFactory? tcpClientFactory = null)
: this(ip, port, TsapPair.GetDefaultTsapPair(cpu, rack, slot), tcpClientFactory)
{
if (!Enum.IsDefined(typeof(CpuType), cpu))
throw new ArgumentException(
Expand All @@ -162,7 +168,9 @@ public Plc(CpuType cpu, string ip, int port, Int16 rack, Int16 slot)
/// </summary>
/// <param name="ip">Ip address of the PLC</param>
/// <param name="tsapPair">The TSAP addresses used for the connection request.</param>
public Plc(string ip, TsapPair tsapPair) : this(ip, DefaultPort, tsapPair)
/// <param name="tcpClientFactory">Factory to provide the underlying <see cref="ITcpClient"/> for network communication.</param>
public Plc(string ip, TsapPair tsapPair, ITcpClientFactory? tcpClientFactory = null)
: this(ip, DefaultPort, tsapPair, tcpClientFactory)
{
}

Expand All @@ -173,7 +181,8 @@ public Plc(string ip, TsapPair tsapPair) : this(ip, DefaultPort, tsapPair)
/// <param name="ip">Ip address of the PLC</param>
/// <param name="port">Port number used for the connection, default 102.</param>
/// <param name="tsapPair">The TSAP addresses used for the connection request.</param>
public Plc(string ip, int port, TsapPair tsapPair)
/// <param name="tcpClientFactory">Factory to provide the underlying <see cref="ITcpClient"/> for network communication.</param>
public Plc(string ip, int port, TsapPair tsapPair, ITcpClientFactory? tcpClientFactory = null)
{
if (string.IsNullOrEmpty(ip))
throw new ArgumentException("IP address must valid.", nameof(ip));
Expand All @@ -182,6 +191,7 @@ public Plc(string ip, int port, TsapPair tsapPair)
Port = port;
MaxPDUSize = 240;
TsapPair = tsapPair;
_tcpClientFactory = tcpClientFactory ?? new TcpClientWrapperFactory();
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion S7.Net/PlcAsynchronous.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ await queue.Enqueue(async () =>

private async Task<NetworkStream> ConnectAsync(CancellationToken cancellationToken)
{
tcpClient = new TcpClient();
tcpClient = _tcpClientFactory.Create();
ConfigureConnection();

#if NET5_0_OR_GREATER
Expand Down
21 changes: 21 additions & 0 deletions S7.Net/Tcp/ITcpClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace S7.Net.Tcp
{
public interface ITcpClient
{
public int ReceiveTimeout { get; set; }

public int SendTimeout { get; set; }

public bool Connected { get; }

public void Close();

public Task ConnectAsync(string ip, int port, CancellationToken cancellationToken = default);

public NetworkStream GetStream();
}
}
6 changes: 6 additions & 0 deletions S7.Net/Tcp/ITcpClientFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace S7.Net.Tcp;

public interface ITcpClientFactory
{
ITcpClient Create();
}
24 changes: 24 additions & 0 deletions S7.Net/Tcp/TcpClientWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace S7.Net.Tcp;

internal class TcpClientWrapper : TcpClient, ITcpClient
{
public async Task ConnectAsync(string ip, int port, CancellationToken cancellationToken)
{
#if NET5_0_OR_GREATER
await base.ConnectAsync(ip, port, cancellationToken).ConfigureAwait(false);
#else
await base.ConnectAsync(ip, port).ConfigureAwait(false);
#endif
}

public void Close()
{
#if NET20_OR_GREATER
base.Close();
#endif
}
}
9 changes: 9 additions & 0 deletions S7.Net/Tcp/TcpClientWrapperFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace S7.Net.Tcp;

internal class TcpClientWrapperFactory : ITcpClientFactory
{
public ITcpClient Create()
{
return new TcpClientWrapper();
}
}
Loading