Reliable PLC Reachability Checks in S7netplus v0.9.0 Without Breaking Active Connections

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();
    }
}

Tags: S7netplus C# Siemens PLC connectivity socket

Posted on Mon, 11 May 2026 14:00:51 +0000 by enemeth