The IsAvailable property in S7netplus v0.9.0 triggers Connect internally, which destroys any existing connection. The following snippet from the library source illustrates the issue:
public bool IsAvailable
{
//TODO: Fix This
get
{
try
{
OpenAsync().GetAwaiter().GetResult();
return true;
}
catch
{
return false;
}
}
}
An earleir version (v0.1.9, 2018-05-14) used a fresh socket per check without disturbing the active connection:
public bool IsAvailable
{
get
{
#if NETFX_CORE
return (!string.IsNullOrWhiteSpace(IP));
#else
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
return Connect(socket) == ErrorCode.NoError;
}
#endif
}
}
You can encapsulate a similar approach in your own wrapper arround v0.9.0 to safely test connectivity.
Socket-Based Availability Check
public bool CheckAvailability
{
get
{
if (_plc == null || string.IsNullOrWhiteSpace(_plc.IP))
return false;
using var probeSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
string msg;
bool available = EstablishConnection(probeSocket, _plc.IP, _plc.Port, out msg) == ErrorCode.NoError;
if (!available)
LastErrorMessage = msg;
return available;
}
}
private static ErrorCode EstablishConnection(Socket sock, string host, int port, out string errorDetail)
{
errorDetail = string.Empty;
try
{
var remoteEp = new IPEndPoint(IPAddress.Parse(host), port);
sock.Connect(remoteEp);
return ErrorCode.NoError;
}
catch (SocketException se)
{
var code = se.SocketErrorCode == SocketError.TimedOut
? ErrorCode.IPAddressNotAvailable
: ErrorCode.ConnectionError;
errorDetail = se.Message;
return code;
}
catch (Exception ex)
{
errorDetail = ex.Message;
return ErrorCode.ConnectionError;
}
}
Adding a Timeout with ICMP Ping
Socket connection timeout control can be tricky. The System.Net.NetworkInformation.Ping class provides a simpler timeout mechanism but only tests IP-level reachability, not a specific port. This is suitable after a logical sesssion is established.
public bool IsPlcReachable
{
get
{
if (_plc == null || string.IsNullOrWhiteSpace(_plc.IP))
return false;
return SendPing(_plc.IP, 1000);
}
}
private static bool SendPing(string targetIp, int timeoutMs)
{
var pinger = new Ping();
try
{
var reply = pinger.Send(targetIp, timeoutMs);
return reply != null && reply.Status == IPStatus.Success;
}
catch (PingException)
{
return false;
}
finally
{
pinger.Dispose();
}
}