titanium-as / TitaniumAS.Opc.Client

Open source .NET client library for OPC DA
MIT License
197 stars 93 forks source link

Server Disconnect #14

Closed LordAshes closed 7 years ago

LordAshes commented 7 years ago

It appears that when the OPC Server disconnects all clients, the codes needs to implement the re-connection / re-subscription process.

To this end there seems to be 2 events on the server object: ConnectionStateChanged and Shutdown.

For us the ConnectionStateChanged event only fired if it was subscribed to before connection and indicated that a connection had been made. The event did not seem to fire when the OPC server was shutdown (i.e. when the connection was disconnected). As a result, this event did not seem to fire at all if made after the initial connection.

For us the Shutdown even fired when implemented is some simple code (expansion of the sample code provided with the project) but when the same event subscription was made in more complex code that uses multiple threads (one for each client), the event did not seem to fire for any of the clients (when the OPC Server was shutdown).

What is the recommended way for detecting OPC Server communication loss and implementing an automatic re-connection?

ghost commented 7 years ago

Hey, this is not an ideal way of doing it but I needed a way to check if the Server was still running since as you mentioned the ConnectionStateChanged event does not seem to fire if the OPC Server is terminated.

I'm using a synchronous approach where I query the OPC Server every x seconds (i.e. 10 seconds) for its Status using the OpcDaSever.GetStatus() - If the server is running this will return "RUNNING" as the ServerState if the OPC Server Connection is fine. Alternately it will throw a "RPC Server Unavailable" Exception if the call does not go through:


            catch (COMException ex)
            {
                var errorString = string.Format("Error: {0} Method name: {1} Object: {2}", ex, methodName,comObject.GetHashCode());
                Log.Error(errorString);
                if (IsRpcError(ex.ErrorCode))
                {
                    object userData = UserData;
                    OnRpcFailed(new RpcFailedEventArgs(userData, ex.ErrorCode));
                }
                throw;
            }

This is triggered by the custom .NotConnected() Exception thrown in the CheckConnected method of the OpcDaServer:

        private void CheckConnected()
        {
            if (!IsConnected)
                throw ExceptionHelper.NotConnected();
        }

Obviously this approach isn't optimal. Ideally you would want the subscriptions to raise the OnConnectionChangeEvent when they start failing due to a loss of connection - but this does allow you to attempt the GetStatus and then catch the RPC Exception, after which you can try to re-connect to the application and handle Connection failure (i.e. call the Disconnect removing groups etc) and keep trying until its back up depending on your needs.

Hope this helps, until we get a proper Event raised I guess this "works".

alexey-titov commented 7 years ago

The Shutdown event indicates that an OPC server sends Shutdown notification to clients. It can happens when OPC server (not client) stopped in regular way. Not all OPC servers support this feature.

The ConnectionStateChanged indicates that OpcDaServer object is connected or disconnected from actual OPC Server. It works fine in many cases, for example we try to determine failure of RPC proxies and generate ConnectionStateChanged and Shutdownevents.

The terndrup's approach with GetStatus can help it the case when Shutdown feature not supported.